chainwright 0.9.12 → 0.10.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/README.md +47 -0
- package/dist/cli/index.js +10 -9
- package/dist/core/index.d.ts +1 -1
- package/dist/{types-DK8rutb5.d.ts → types-aoLElQ63.d.ts} +7 -0
- package/dist/wallets/keplr/index.d.ts +3 -3
- package/dist/wallets/keplr/index.js +3 -3
- package/dist/wallets/metamask/index.d.ts +3 -3
- package/dist/wallets/metamask/index.js +3 -3
- package/dist/wallets/meteor/index.d.ts +3 -3
- package/dist/wallets/meteor/index.js +7 -7
- package/dist/wallets/petra/index.d.ts +3 -3
- package/dist/wallets/petra/index.js +3 -3
- package/dist/wallets/phantom/index.d.ts +3 -3
- package/dist/wallets/phantom/index.js +2 -2
- package/dist/wallets/solflare/index.d.ts +3 -3
- package/dist/wallets/solflare/index.js +4 -4
- package/dist/{worker-scope-context-CNAfiliw.d.ts → worker-scope-context-DSkOcWf-.d.ts} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -178,6 +178,53 @@ export default defineWalletSetup(
|
|
|
178
178
|
);
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
+
**For custom wallet extension download URL and local path**
|
|
182
|
+
|
|
183
|
+
For security reasons, you might choose not to use the same wallet extension source that Chainwright uses internally. To fix this, you can provide your own wallet extension source via a download URL or a locally stored wallet extension.
|
|
184
|
+
|
|
185
|
+
>[!NOTE]
|
|
186
|
+
You must ensure that the version of the extension you provide matches the one Chainwright uses internally.
|
|
187
|
+
|
|
188
|
+
These are Chainwright's wallet extensions and their versions:
|
|
189
|
+
|
|
190
|
+
- **MetaMask**: v13.33.0
|
|
191
|
+
- **Petra**: v2.4.8
|
|
192
|
+
- **Phantom**: v26.10.0
|
|
193
|
+
- **Solflare**: v2.19.1
|
|
194
|
+
- **Meteor**: v0.7.0
|
|
195
|
+
- **Keplr**: v0.13.3
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { defineWalletSetup } from "chainwright/core";
|
|
201
|
+
import { Metamask } from "chainwright/metamask";
|
|
202
|
+
|
|
203
|
+
const PASSWORD = "test1234"; // For Petra wallet, you have to use a strong password. e.g. PlayerPetra45!!
|
|
204
|
+
const SEED_PHRASE = "test test test test test test test test test test test test test";
|
|
205
|
+
|
|
206
|
+
export default defineWalletSetup(
|
|
207
|
+
PASSWORD,
|
|
208
|
+
async ({ walletPage }) => {
|
|
209
|
+
const metamask = new Metamask(walletPage);
|
|
210
|
+
|
|
211
|
+
await metamask.onboard({
|
|
212
|
+
mode: "import",
|
|
213
|
+
secretRecoveryPhrase: SEED_PHRASE,
|
|
214
|
+
mainAccountName: "Main",
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
extensionSource: {
|
|
219
|
+
localPath: "Your local path here",
|
|
220
|
+
// OR
|
|
221
|
+
downloadUrl: "Download URL here",
|
|
222
|
+
sha256: "Expectd SHA-256 hash here"
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
);
|
|
226
|
+
```
|
|
227
|
+
|
|
181
228
|
### 2. Build wallet cache
|
|
182
229
|
|
|
183
230
|
Run setup with the CLI (Supports **npx**, **bun**, **pnpm**, and **yarn**):
|
package/dist/cli/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --import tsx
|
|
2
|
-
import z from"path";import{styleText as g}from"util";import
|
|
3
|
-
${a}`,{encoding:"utf-8"})}catch(
|
|
4
|
-
`));return await Promise.all(
|
|
5
|
-
`));return await t.close(),
|
|
6
|
-
|
|
2
|
+
import z from"path";import{styleText as g}from"util";import ke from"@inquirer/checkbox";import{Command as Me}from"commander";import b from"fs";import H from"path";import{fileURLToPath as re}from"url";var ae=re(import.meta.url),ne=H.dirname(ae),P=H.resolve(ne,"..","..","generated-profile-name.types.ts"),se=e=>e.replace(/(^\w)/g,o=>o.toUpperCase());async function G({walletName:e,profileName:o}){let t=se(e),a=`export type ${t}Profiles = "${o}";`;if(b.existsSync(P)){let r=b.readFileSync(P,"utf-8"),p=r.match(new RegExp(`export type ${t}Profiles = ("[^"]+"(?:\\s*\\|\\s*"[^"]+")*)`));if(p){let n=p[0];if(!n.includes(`"${o}"`)){let m=n.concat(` | "${o}"`),s=r.replace(n,m);try{b.writeFileSync(P,s)}catch(i){console.error("Error updating existing profile name type: ",i)}}}else try{b.appendFileSync(P,`
|
|
3
|
+
${a}`,{encoding:"utf-8"})}catch(n){console.error("Error appending new profile name type: ",n)}}else try{b.writeFileSync(P,a)}catch(r){console.error("Error writing new profile name type: ",r)}}import le from"path";import{pathToFileURL as ce}from"url";import{styleText as pe}from"util";import{glob as me}from"glob";import ie from"path";function D(e){let o=ie.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 fe=e=>e.replace(/\\/g,"/"),de=e=>`${fe(le.resolve(e))}/**/*.setup.{ts,js,}`,ue=e=>import(new URL(ce(e)).href);async function N({walletSetupDir:e,selectedWallets:o}){let t=de(e),a=(await me(t,{dot:!0,absolute:!0,nodir:!0,windowsPathsNoEscape:!0})).sort(),r=o.length===1?o[0]:o,p=["metamask","solflare","petra","meteor","keplr","phantom"];Array.isArray(r)&&r.forEach(i=>{p.includes(i)||console.warn(pe("magenta",`Unsupported wallet: "${i}". Supported wallets are: ${p.join(", ")}`,{validateStream:!1}))});let m=(r==="all"?a:Array.isArray(r)?a.filter(i=>r.some(l=>i.includes(l))):a.filter(i=>i.includes(r))).map(i=>({filePath:i,walletName:D(i)}));if(!m.length||m.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(m.map(async({filePath:i,walletName:l})=>{let f=await(await ue(i)).default,{fn:y,config:w,password:h}=f;return{walletName:l,fileList:m,config:w,walletPassword:h,setupFunction:y}}))}import S from"fs";import O from"path";import{styleText as E}from"util";import{chromium as Ue}from"@playwright/test";import Le from"path";var K=".wallet-cache";var V="wallet-setup",X="13.33.0",Y="0.13.3",W="https://github.com/amaify/chainwright/releases/download/v0.1.0/",we=`https://github.com/chainapsis/keplr-wallet/releases/download/v${Y}/`,he=`https://github.com/MetaMask/metamask-extension/releases/download/v${X}/`,ge=`${he}metamask-chrome-${X}.zip`,ye=`${W}solflare-wallet-extension-v2.19.1.zip`,xe=`${W}petra-wallet-extension-v2.4.8.zip`,Se=`${W}phantom-wallet-extension-v26.10.0.zip`,Ee=`${W}meteor-wallet-extension-v0.7.0.zip`,Ae=`${we}keplr-extension-manifest-v3-v${Y}.zip`,T={metamask:{downloadUrl:ge,extensionName:"MetaMask",sha256:"400a71744b0f3a107e5fcb33871c25a50a8da96f9633df1b9bdef58b555441c1"},solflare:{downloadUrl:ye,extensionName:"Solflare Wallet",sha256:"08c90d006638f719245250552bb942ddc8ec287c586da8624b771592faffbcf8"},petra:{downloadUrl:xe,extensionName:"Petra Aptos Wallet",sha256:"cb7c876e1b3e6e0f394c8ca446f99bac58a0e9da0411eda8d664b4a21956e53f"},phantom:{downloadUrl:Se,extensionName:"Phantom",sha256:"29d5475f4957d3fc888f9e69766c8ff96865c9572ac3021c9fd7c175cf97e955"},meteor:{downloadUrl:Ee,extensionName:"Meteor Wallet",sha256:"133eed4119accd21fbae9dd9ed9e9228a83c3ebd783c6407d708c18c8e20ce05"},keplr:{downloadUrl:Ae,extensionName:"Keplr",sha256:"df601d806aea6b345ab0fc53504c58ecae1aa0c108d8b3f02dd743e0fcbb0751"}};function _(e){return Le.resolve(process.cwd(),K,e)}import{z as R}from"zod";var ve=R.object({id:R.string(),name:R.string()}),$e=R.array(ve);async function q(e,o){let t=await e.newPage();await t.goto("chrome://extensions");let a=await t.evaluate("chrome.management.getAll()"),r=$e.parse(a),p=r.find(n=>n.name.toLowerCase()===o.toLowerCase());if(!p)throw new Error([`[GetExtensionId] Extension with name ${o} not found.`,`Available extensions: ${r.map(n=>n.name).join(", ")}`].join(`
|
|
5
|
+
`));return await t.close(),p.id}import L from"fs";import k from"path";import{styleText as v}from"util";import Ie from"adm-zip";import{createWriteStream as be}from"fs";import{Readable as Pe}from"stream";import{styleText as U}from"util";import _e from"cli-progress";var Ce=12e4;async function Z({url:e,destination:o}){let t=new AbortController,a=setTimeout(()=>t.abort(),Ce),r=await fetch(e,{redirect:"follow",signal:t.signal});r.ok||(console.error(U("redBright",`\u274C Download failed: HTTP ${r.status}`,{validateStream:!1})),t.abort(),process.exit(1));let p=parseInt(r.headers.get("content-length")||"0",10),n=0,m=Pe.fromWeb(r.body);try{let s=new _e.SingleBar({format:`Downloading ${U("cyan","{bar}",{validateStream:!1})} {percentage}%`,clearOnComplete:!0,barCompleteChar:"\u2588",barIncompleteChar:"\u2591",hideCursor:!0});s.start(p,0,{speed:"N/A"}),await new Promise((i,l)=>{let c=be(o);m.pipe(c),m.on("data",f=>{n+=f.length,s.update(n)}),c.on("error",l),c.on("finish",()=>{s.stop(),i(void 0)})})}catch(s){console.error(U("redBright",`\u274C Download failed: ${s}`,{validateStream:!1})),process.exit(1)}finally{clearTimeout(a)}}import{createHash as Fe}from"crypto";import{createReadStream as We}from"fs";var Te=/^[a-f0-9]{64}$/i;async function Re(e){let o=Fe("sha256"),t=We(e);return await new Promise((a,r)=>{t.on("data",p=>o.update(p)),t.on("error",r),t.on("end",()=>a(o.digest("hex")))})}async function J({filePath:e,expectedSha256:o,label:t}){if(!Te.test(o))throw new Error(`${t} has an invalid SHA-256 checksum.`);let a=await Re(e);if(a.toLowerCase()!==o.toLowerCase())throw new Error([`${t} failed integrity verification.`,`Expected SHA-256: ${o}`,`Actual SHA-256: ${a}`,"The file was not extracted."].join(`
|
|
6
|
+
`));return a}var $=!1,M="";async function Q({downloadUrl:e,name:o,force:t,extensionSource:a}){let r=_(o),p=T[o],n=p.extensionName,m=k.join(r,`${o}-extension.zip`),s=k.join(r,`${o}-extension`),i=a&&"downloadUrl"in a,l=i?a.downloadUrl:e,c=a&&"localPath"in a?a.localPath:void 0,f=i?a.sha256:p.sha256;if($?M!==n&&$&&($=!1,M=n):M=n,t&&L.existsSync(r)&&!$&&(L.rmSync(r,{recursive:!0}),console.info(v("magenta",`\u{1F9F9} Removed ${n} because of the force flag`,{validateStream:!1}))),L.existsSync(r)||L.mkdir(r,{recursive:!0},w=>{if(w)throw Error("Failed to create cache directory");console.info(`\u2705 ${n} Cache directory created successfully.`)}),L.existsSync(s)?console.info(`\u2705 ${n} Version is downloaded already.`):c?console.info(v("cyanBright",`Using the local ${o} extension zip file`,{validateStream:!1})):(console.info(v("cyanBright",`\u{1F4E5} Downloading ${n} extension...`,{validateStream:!1})),await Z({url:l,destination:m}),await J({filePath:m,expectedSha256:f,label:`${n} extension`}),console.info(v("green",`\u2705 ${o.toUpperCase()} Extension downloaded successfully.`,{validateStream:!1}))),!L.existsSync(s))console.info("\u{1F4E6} Extracting extension..."),new Ie(c||m).extractAllTo(s,!0),console.info(`\u2705 ${n} Extension extracted successfully.`);else{if($)return console.info(v("magentaBright",`Using the cached ${n} extension for profile creation.`,{validateStream:!1})),s;console.info(v("yellow",`\u26A0\uFE0F Skipping ${n} cache creation: Cache already exists at ${s}. Use --force to overwrite.`,{validateStream:!1}))}let y=k.join(s,"manifest.json");if(!L.existsSync(y))throw new Error(`\u274C (${n}) Invalid extension: manifest.json not found`);return $=!0,s}import{styleText as Oe}from"util";function B(e){return new Promise(o=>setTimeout(o,e))}var I=20,De=6e3,ee=4e3;async function Ne(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 te(e,o){let t=0,a=null;if(o==="meteor")return await e.newPage();for(console.info(`Waiting ${ee}ms for browser to initialize...`),await B(ee);t<=I;)try{if(console.info(`Looking for extension page (attempt ${t+1}/${I})...`),t===I)throw new Error("Extension page not found after maximum retries");let r=await Ne(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}/${I})...`),await B(De))}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(Oe("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:p}){let{downloadUrl:n,extensionName:m}=T[e],s=_(e),i=t?.profileName,l=i?`${i}`:"wallet-data",c=O.resolve(s,"extension-id.txt"),f=O.resolve(s,"extension-path.txt"),y=O.resolve(s,"password.txt"),w=O.resolve(s,l),h=await Q({downloadUrl:n,name:e,force:o,extensionSource:t?.extensionSource}),x=[`--disable-extensions-except=${h}`,`--load-extension=${h}`];if(S.existsSync(w)&&a.length>1)throw Error([E("yellowBright",[`\u274C ${l} directory already exists for ${m}.`,`
|
|
7
|
+
To setup another wallet profile, add a profile name to the wallet setup function.`,E(["blueBright","italic"],'Example: defineWalletSetup(async ({ context, walletPage }) => { ... }, { profileName: "profile-name" });'),E("italic","You can also use the --force flag to overwrite the existing cache.")].join(`
|
|
7
8
|
`),{validateStream:!1})].join(`
|
|
8
|
-
`));if(
|
|
9
|
-
Setting up cache for ${
|
|
10
|
-
\u274C Failed to setup cache for ${
|
|
11
|
-
\u274C Attempt ${
|
|
9
|
+
`));if(S.existsSync(w))return;let A=await Ue.launchPersistentContext(w,{headless:!1,args:x,slowMo:t?.slowMo??0});console.info(E("magentaBright",`\u{1F9E9}\u{1F680} Starting Chrome extension for ${e.toUpperCase()}`,{validateStream:!1}));let oe=await te(A,e);if(!S.existsSync(c)&&!S.existsSync(f)){let F=await q(A,m);console.info(E("magentaBright",`\u{1F194} ${m} extension ID: ${F}`,{validateStream:!1})),S.writeFileSync(c,F,"utf-8"),console.info(E("cyanBright",`\u{1F4BE} Saved extension ID to: ${c}`,{validateStream:!1})),S.writeFileSync(f,h,"utf-8"),console.info(E("blueBright",`\u{1F4C1} Saved extension Path to: ${f}`,{validateStream:!1})),S.writeFileSync(y,r,"utf-8"),console.info(E("yellowBright",`\u{1F511} Saved ${e} password to: ${y}`,{validateStream:!1}))}try{await p({context:A,walletPage:oe})}catch(F){throw await A.close(),S.rmSync(s,{force:!0,recursive:!0}),Error(`Error setting up wallet: ${F.message}`)}await A.close()}var Be=z.resolve(process.cwd(),"tests",V),C=1;async function je(){let e=new Me;e.name(g("yellow","Chainwright")).description(g("green","A CLI tool for setting up wallet cache for E2E testing of web3 applications")).version(g("blue","0.0.0")),e.argument("[dir]","Directory containing the wallet setup functions",z.resolve(Be)).option("--headless","Build cache in the headless browser mode. Alternatively, set the `HEADLESS` env variable to `true`",!1).option("-f, --force","Force the creation of cache even if it already exists",!1).option("-a, --all","Setup all wallets","all").option("--kp, --keplr","Setup Keplr","keplr").option("-m, --metamask","Setup MetaMask","metamask").option("--mt, --meteor","Setup Meteor","meteor").option("--pt, --petra","Setup Petra","petra").option("--ph, --phantom","Setup Phantom","phantom").option("-s, --solflare","Setup Solflare","solflare").option("--wls, --wallets <wallets...>","Specify wallets to setup (e.g., --wallets keplr metamask)").action(async(o,t)=>{let a=["all","metamask","solflare","petra","meteor","keplr","phantom"],r=Object.keys(t).filter(l=>a.includes(l)?t[l]===!0:!1),p=r.length>0,n=t.wallets,m=n||(p?r:await ke({message:"Select the wallet you want to setup",choices:[{name:"All",value:"all"},{name:"Keplr",value:"keplr"},{name:"MetaMask",value:"metamask"},{name:"Meteor",value:"meteor"},{name:"Petra",value:"petra"},{name:"Phantom",value:"phantom"},{name:"Solflare",value:"solflare"}],validate:l=>{let c=l.map(f=>f.value);return c.includes("all")&&c.length>1?'Select either "All" or specific wallets, not both.':!0},pageSize:10})),s=z.resolve(process.cwd(),o);t.headless&&(process.env.HEADLESS=!0);let i=await N({walletSetupDir:s,selectedWallets:m});for(let{walletName:l,config:c,walletPassword:f,setupFunction:y,fileList:w}of i)try{console.info(g("cyanBright",`
|
|
10
|
+
Setting up cache for ${l}...`,{validateStream:!1})),await j({walletName:l,config:c,setupFunction:y,fileList:w,force:t.force,walletPassword:f}),c.profileName&&await G({walletName:l,profileName:c.profileName})}catch(h){if(h.message.includes("directory already exists")&&console.warn(h.message),!h.message.includes("directory already exists")){console.error(g("redBright",`
|
|
11
|
+
\u274C Failed to setup cache for ${l}: ${h.message}`,{validateStream:!1}));let x=0;for(;C>x;){console.info(`${g("yellow",`Retry Attempt ${x+1} of ${C} for ${l}...`,{validateStream:!1})}`),console.info(g("yellow","Retrying wallet setup...",{validateStream:!1}));try{await j({walletName:l,config:c,setupFunction:y,fileList:w,force:t.force,walletPassword:f});break}catch(A){x+1<C&&console.error(g("redBright",`
|
|
12
|
+
\u274C Attempt ${x+1} failed! Retrying...`,{validateStream:!1})),x++,x===C&&console.error(g("redBright",`\u274C Failed to setup cache after ${C} attempts for ${l}: ${A.message}`,{validateStream:!1}))}}}}}),await e.parseAsync(process.argv)}je().catch(e=>console.error(g("redBright",`Failed to run the CLI: ${e.message})`,{validateStream:!1})));export{je as clientEntry};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as WalletSetupFunction, a as WalletSetupConfig } from '../types-
|
|
1
|
+
import { b as WalletSetupFunction, a as WalletSetupConfig } from '../types-aoLElQ63.js';
|
|
2
2
|
import { Fixtures, TestType } from '@playwright/test';
|
|
3
3
|
|
|
4
4
|
declare function defineWalletSetup(password: string, fn: WalletSetupFunction, config?: WalletSetupConfig): Promise<{
|
|
@@ -7,9 +7,16 @@ type Args = {
|
|
|
7
7
|
walletPage: Page;
|
|
8
8
|
};
|
|
9
9
|
type WalletSetupFunction = ({ context, walletPage }: Args) => Promise<void>;
|
|
10
|
+
type ExtensionSource = {
|
|
11
|
+
localPath: string;
|
|
12
|
+
} | {
|
|
13
|
+
downloadUrl: string;
|
|
14
|
+
sha256: string;
|
|
15
|
+
};
|
|
10
16
|
type WalletSetupConfig = {
|
|
11
17
|
profileName?: string;
|
|
12
18
|
slowMo?: number;
|
|
19
|
+
extensionSource?: ExtensionSource;
|
|
13
20
|
};
|
|
14
21
|
type WalletProfileFixtureArgs = {
|
|
15
22
|
slowMo?: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { BrowserContext, Page } from '@playwright/test';
|
|
6
6
|
import z from 'zod';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import Q from"fs";import bt from"path";import{chromium as kt}from"@playwright/test";import At from"path";var J=".wallet-cache",Y=".wallet-context";var X="13.33.0",E="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Ut=`https://github.com/MetaMask/metamask-extension/releases/download/v${X}/metamask-chrome-${X}.zip`,Mt=`${E}solflare-wallet-extension-v2.19.1.zip`,Ht=`${E}petra-wallet-extension-v2.4.8.zip`,jt=`${E}phantom-wallet-extension-v26.10.0.zip`,zt=`${E}meteor-wallet-extension-v0.7.0.zip`,Gt=`${E}keplr-wallet-extension-v0.13.3.zip`;async function I(t){return At.resolve(process.cwd(),Y,t)}import Pt from"path";function y(t){return Pt.resolve(process.cwd(),J,t)}import q from"fs";import vt from"path";async function N(t){try{let o=y(t),e=vt.resolve(o,"extension-path.txt");if(!q.existsSync(e))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=q.readFileSync(e,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function Z({wallet:t,workerInfo:o,profileName:e,slowMo:a}){let r=await I(o.workerIndex.toString()),n=y(t.name),l=bt.resolve(n,e??"wallet-data");if(!Q.existsSync(l))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);Q.cpSync(l,r,{recursive:!0,force:!0});let m=await N(t.name),p=await kt.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${m}`],slowMo:process.env.HEADLESS?0:a}),d=await t.indexUrl(),i=p.pages()[0];return i||(i=await p.newPage()),await i.goto(d),{context:p,walletPage:i,contextPath:r}}import{expect as rt}from"@playwright/test";function S(t){return new Promise(o=>setTimeout(o,t))}async function k(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import tt from"fs";import St from"path";async function _(t){let o=y(t),e=St.resolve(o,"password.txt");try{if(!tt.existsSync(e))throw new Error("\u274C password.txt not found. Run setup script first.");return tt.readFileSync(e,"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 et({context:t,path:o,locator:e}){let a;try{await Ct.poll(async()=>(a=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(o)),!!a),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).map(n=>n.url());throw new Error(`Popup page with path "${o}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!a)throw new Error(`Popup page with path ${o} not found in context.`);return await Bt(a,e),await a.setViewportSize({width:360,height:592}),a}async function Bt(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 ot from"fs";import Tt from"path";async function at(t){let o=y(t),e=Tt.resolve(o,"extension-id.txt");try{if(!ot.existsSync(e))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return ot.readFileSync(e,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var A=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 at(this.name)}async promptPage(o){let e=await this.promptUrl();return await et({context:o,path:e,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 Wt(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async function C({page:t,privateKey:o,walletName:e,chains:a,mode:r="onboard"}){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(o),await nt({page:t,walletName:e,mode:r,chains:a})}async function B({page:t,seedPhrase:o,walletName:e,chains:a,mode:r="onboard"}){await t.locator(g.importExistingWalletButton).click(),await t.locator(g.usePrivateKeyButton).click(),await t.getByRole("button",{name:"12 words",exact:!0}).click();let p=t.locator("input[type='password']"),d=o.split(" ");await p.first().fill(d[0]),await p.first().press("Tab");for(let i=1;i<d.length;i++){let u=p.nth(i),h=d[i];await u.fill(h),i<d.length-1&&await u.press("Tab")}await nt({page:t,walletName:e,mode:r,chains:a})}async function nt({page:t,walletName:o,mode:e,chains:a}){let r=new A,n=await _("keplr");if(await t.getByRole("button",{name:"Import",exact:!0}).click(),await t.locator(g.walletNameInput).fill(o),e==="onboard"){let w=t.locator(g.walletPasswordInput),b=t.locator(g.confirmWalletPasswordInput);await w.fill(n),await b.fill(n)}await t.locator(g.nextButton).click();let d=t.locator("div:has-text('All Native Chains')").nth(-4),i=t.locator("div[cursor='pointer']:has-text('Cosmos Hub')"),u=await d.locator("input[type='checkbox']").getAttribute("checked"),h=await i.locator("input[type='checkbox']").getAttribute("checked");u!==null&&await d.click(),h!==null&&await i.click();let x=t.locator(g.searchNetworkInput);for(let w of a){await x.fill(w);let v=t.locator("div[class='simplebar-content']").locator("div[cursor] > div").first().locator("div").filter({hasText:new RegExp(`^${Wt(w)}$`,"i")}).nth(2).locator("../../../../..");await v.waitFor({state:"visible",timeout:2e4}),await v.locator("input[type='checkbox']").getAttribute("checked")===null&&await v.click()}let f=t.locator(g.saveButton);if(await f.scrollIntoViewIfNeeded(),await f.click(),await S(2e3),e==="onboard"){await t.goto(await r.indexUrl());return}if(e==="add-account-single"){let w=t.locator(g.finishButton);await w.waitFor({state:"visible",timeout:2e4}),await rt(w).toBeEnabled({timeout:2e4}),await w.click()}}async function K(t){let e=await new A().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 l;if(await rt.poll(async()=>(l=t.context().pages().find(m=>m.url().match(e)),!!l),{timeout:3e4}).toBe(!0).catch(m=>{console.error(`Failed to find onboarding page with URL matching ${e}. Original error: ${m}`)}),!l)throw new Error(`Onboarding page not found. Expected URL: ${e}`);return await k(l),await l.bringToFront(),l}async function it({page:t,chains:o,walletName:e,mode:a,...r}){let n=await K(t);"privateKey"in r&&await C({page:n,privateKey:r.privateKey,walletName:e,chains:o,mode:a}),"seedPhrase"in r&&await B({page:n,seedPhrase:r.seedPhrase,walletName:e,chains:o,mode:a}),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 Et}from"@playwright/test";var O={approveButton:"button:has-text('Approve')",rejectButton:"button[color='secondary']"};async function st(t){let o=t.locator(O.approveButton);await Et(o).toBeEnabled({timeout:2e4}),await o.click()}async function ct(t){t.getByRole("button",{name:"Approve",exact:!0}).click(),await S(1e3)}import{expect as It}from"@playwright/test";import P from"zod";var lt=P.discriminatedUnion("chain",[P.object({chain:P.literal(["Injective","Injective (Testnet)","Polygon"]),walletName:P.string().min(1,"Wallet name cannot be an empty string")}),P.object({chain:P.literal(["Bitcoin","Bitcoin Signet","Bitcoin Testnet"]),chainTag:P.literal(["Taproot","Native Segwit"]),walletName:P.string().min(1,"Wallet name cannot be an empty string")})]),pt=P.object({currentAccountName:P.string().min(1,"Current account name cannot be an empty string"),newAccountName:P.string().min(1,"New account name cannot be an empty string")});async function dt({page:t,...o}){let e=lt.parse({...o});await t.getByRole("textbox",{name:"Search for asset or chain (i.e. ATOM, Cosmos)",exact:!0}).fill(e.chain);let r=t.locator(`div:has-text("${e.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 "${e.chain}" is activated.`);let l=await r.locator("div").all();It(l.length).toBeGreaterThan(0),await t.locator(`div:has(div:has-text('${e.walletName}'))`).nth(-3).locator("div:has(> div > svg)").click();let d=t.locator("div:has(> div[data-simplebar='init'])").last(),u=d.locator("div:has(> div > input)").locator("input");await u.fill(e.chain);let x=await d.locator("div[cursor='pointer']",{hasText:e.chain}).all(),f;for(let b of x){let v;"chainTag"in o&&(v=o.chainTag);let $=b.locator("div",{hasText:e.chain}).last(),V=v?b.locator("div",{hasText:v}).last():null,z=(V?await V?.isVisible().catch(()=>!1):!1)?await V?.textContent():null,G=await $.textContent(),xt=z?`${G} ${z}`:G,yt=v?`${e.chain} ${v}`:e.chain;if(xt===yt){f=$.locator("xpath=../../../.."),await u.clear();break}}if(!f)throw Error(`Address for ${e.walletName} account on "${e.chain}" chain not found.`);return await f.hover(),await f.scrollIntoViewIfNeeded(),await f.click(),await f.waitFor({state:"detached",timeout:7e3}),await t.evaluate(async()=>await navigator.clipboard.readText())}var F={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'])"},U={unlockButton:"button[type='submit']:has-text('Unlock')",passwordInput:"input[placeholder='Type Your Password']"};async function mt(t){await t.locator(F.openSidebarMenuButton).click(),await t.locator(F.lockWalletButton).nth(-1).click(),await t.getByText("Welcome Back").waitFor({state:"visible",timeout:3e4})}import{styleText as ut}from"util";import{expect as Ft}from"@playwright/test";async function R(t,o){let e=t.locator("div[color]").nth(1);if(await e.textContent()===o){console.info(`
|
|
2
|
-
Already on ${o} account. No need to switch.`);return}await e.click();let r=t.locator("div[class='simplebar-content'] > div").locator("> div",{hasText:o});if(!await r.isVisible().catch(()=>!1))throw new Error(`Account "${o}" not found. Make sure the account is onboarded or verify the account name.`);let l=t.locator("div:has-text('Select Wallet')").last();await r.click(),await l.waitFor({state:"detached",timeout:3e4})}async function M({page:t,onboard:o}){if(console.info(
|
|
3
|
-
Keplr onboarding started...`,{validateStream:!1})),o.length===1){let e=o[0];if(e&&e.mode==="privateKey"){let{privateKey:a,walletName:r,chains:n}=e;await
|
|
1
|
+
import Z from"fs";import Bt from"path";import{chromium as Ct}from"@playwright/test";import vt from"path";var X=".wallet-cache",J=".wallet-context";var Y="13.33.0",q="0.13.3",_="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Pt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${q}/`,bt=`https://github.com/MetaMask/metamask-extension/releases/download/v${Y}/`,jt=`${bt}metamask-chrome-${Y}.zip`,zt=`${_}solflare-wallet-extension-v2.19.1.zip`,Gt=`${_}petra-wallet-extension-v2.4.8.zip`,Xt=`${_}phantom-wallet-extension-v26.10.0.zip`,Jt=`${_}meteor-wallet-extension-v0.7.0.zip`,Yt=`${Pt}keplr-extension-manifest-v3-v${q}.zip`;async function E(t){return vt.resolve(process.cwd(),J,t)}import kt from"path";function y(t){return kt.resolve(process.cwd(),X,t)}import Q from"fs";import St from"path";async function F(t){try{let o=y(t),e=St.resolve(o,"extension-path.txt");if(!Q.existsSync(e))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=Q.readFileSync(e,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function tt({wallet:t,workerInfo:o,profileName:e,slowMo:a}){let r=await E(o.workerIndex.toString()),n=y(t.name),l=Bt.resolve(n,e??"wallet-data");if(!Z.existsSync(l))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);Z.cpSync(l,r,{recursive:!0,force:!0});let m=await F(t.name),p=await Ct.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${m}`],slowMo:process.env.HEADLESS?0:a}),d=await t.indexUrl(),i=p.pages()[0];return i||(i=await p.newPage()),await i.goto(d),{context:p,walletPage:i,contextPath:r}}import{expect as nt}from"@playwright/test";function S(t){return new Promise(o=>setTimeout(o,t))}async function k(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import et from"fs";import Tt from"path";async function N(t){let o=y(t),e=Tt.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(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Wt}from"@playwright/test";async function ot({context:t,path:o,locator:e}){let a;try{await Wt.poll(async()=>(a=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(o)),!!a),{timeout:3e4}).toBe(!0)}catch{let r=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).map(n=>n.url());throw new Error(`Popup page with path "${o}" not found in context after 30s. Pages in context: ${JSON.stringify(r)}`)}if(!a)throw new Error(`Popup page with path ${o} not found in context.`);return await Et(a,e),await a.setViewportSize({width:360,height:592}),a}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 at from"fs";import It from"path";async function rt(t){let o=y(t),e=It.resolve(o,"extension-id.txt");try{if(!at.existsSync(e))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(e,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var A=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(o){let e=await this.promptUrl();return await ot({context:o,path:e,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 _t(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async function B({page:t,privateKey:o,walletName:e,chains:a,mode:r="onboard"}){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(o),await it({page:t,walletName:e,mode:r,chains:a})}async function C({page:t,seedPhrase:o,walletName:e,chains:a,mode:r="onboard"}){await t.locator(g.importExistingWalletButton).click(),await t.locator(g.usePrivateKeyButton).click(),await t.getByRole("button",{name:"12 words",exact:!0}).click();let p=t.locator("input[type='password']"),d=o.split(" ");await p.first().fill(d[0]),await p.first().press("Tab");for(let i=1;i<d.length;i++){let u=p.nth(i),h=d[i];await u.fill(h),i<d.length-1&&await u.press("Tab")}await it({page:t,walletName:e,mode:r,chains:a})}async function it({page:t,walletName:o,mode:e,chains:a}){let r=new A,n=await N("keplr");if(await t.getByRole("button",{name:"Import",exact:!0}).click(),await t.locator(g.walletNameInput).fill(o),e==="onboard"){let w=t.locator(g.walletPasswordInput),v=t.locator(g.confirmWalletPasswordInput);await w.fill(n),await v.fill(n)}await t.locator(g.nextButton).click();let d=t.locator("div:has-text('All Native Chains')").nth(-4),i=t.locator("div[cursor='pointer']:has-text('Cosmos Hub')"),u=await d.locator("input[type='checkbox']").getAttribute("checked"),h=await i.locator("input[type='checkbox']").getAttribute("checked");u!==null&&await d.click(),h!==null&&await i.click();let x=t.locator(g.searchNetworkInput);for(let w of a){await x.fill(w);let b=t.locator("div[class='simplebar-content']").locator("div[cursor] > div").first().locator("div").filter({hasText:new RegExp(`^${_t(w)}$`,"i")}).nth(2).locator("../../../../..");await b.waitFor({state:"visible",timeout:2e4}),await b.locator("input[type='checkbox']").getAttribute("checked")===null&&await b.click()}let f=t.locator(g.saveButton);if(await f.scrollIntoViewIfNeeded(),await f.click(),await S(2e3),e==="onboard"){await t.goto(await r.indexUrl());return}if(e==="add-account-single"){let w=t.locator(g.finishButton);await w.waitFor({state:"visible",timeout:2e4}),await nt(w).toBeEnabled({timeout:2e4}),await w.click()}}async function K(t){let e=await new A().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 l;if(await nt.poll(async()=>(l=t.context().pages().find(m=>m.url().match(e)),!!l),{timeout:3e4}).toBe(!0).catch(m=>{console.error(`Failed to find onboarding page with URL matching ${e}. Original error: ${m}`)}),!l)throw new Error(`Onboarding page not found. Expected URL: ${e}`);return await k(l),await l.bringToFront(),l}async function ct({page:t,chains:o,walletName:e,mode:a,...r}){let n=await K(t);"privateKey"in r&&await B({page:n,privateKey:r.privateKey,walletName:e,chains:o,mode:a}),"seedPhrase"in r&&await C({page:n,seedPhrase:r.seedPhrase,walletName:e,chains:o,mode:a}),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 Ft}from"@playwright/test";var L={approveButton:"button:has-text('Approve')",rejectButton:"button[color='secondary']"};async function st(t){let o=t.locator(L.approveButton);await Ft(o).toBeEnabled({timeout:2e4}),await o.click()}async function lt(t){t.getByRole("button",{name:"Approve",exact:!0}).click(),await S(1e3)}import{expect as Nt}from"@playwright/test";import P from"zod";var pt=P.discriminatedUnion("chain",[P.object({chain:P.literal(["Injective","Injective (Testnet)","Polygon"]),walletName:P.string().min(1,"Wallet name cannot be an empty string")}),P.object({chain:P.literal(["Bitcoin","Bitcoin Signet","Bitcoin Testnet"]),chainTag:P.literal(["Taproot","Native Segwit"]),walletName:P.string().min(1,"Wallet name cannot be an empty string")})]),dt=P.object({currentAccountName:P.string().min(1,"Current account name cannot be an empty string"),newAccountName:P.string().min(1,"New account name cannot be an empty string")});async function mt({page:t,...o}){let e=pt.parse({...o});await t.getByRole("textbox",{name:"Search for asset or chain (i.e. ATOM, Cosmos)",exact:!0}).fill(e.chain);let r=t.locator(`div:has-text("${e.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 "${e.chain}" is activated.`);let l=await r.locator("div").all();Nt(l.length).toBeGreaterThan(0),await t.locator(`div:has(div:has-text('${e.walletName}'))`).nth(-3).locator("div:has(> div > svg)").click();let d=t.locator("div:has(> div[data-simplebar='init'])").last(),u=d.locator("div:has(> div > input)").locator("input");await u.fill(e.chain);let x=await d.locator("div[cursor='pointer']",{hasText:e.chain}).all(),f;for(let v of x){let b;"chainTag"in o&&(b=o.chainTag);let D=v.locator("div",{hasText:e.chain}).last(),V=b?v.locator("div",{hasText:b}).last():null,z=(V?await V?.isVisible().catch(()=>!1):!1)?await V?.textContent():null,G=await D.textContent(),yt=z?`${G} ${z}`:G,At=b?`${e.chain} ${b}`:e.chain;if(yt===At){f=D.locator("xpath=../../../.."),await u.clear();break}}if(!f)throw Error(`Address for ${e.walletName} account on "${e.chain}" chain not found.`);return await f.hover(),await f.scrollIntoViewIfNeeded(),await f.click(),await f.waitFor({state:"detached",timeout:7e3}),await t.evaluate(async()=>await navigator.clipboard.readText())}var I={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'])"},U={unlockButton:"button[type='submit']:has-text('Unlock')",passwordInput:"input[placeholder='Type Your Password']"};async function ut(t){await t.locator(I.openSidebarMenuButton).click(),await t.locator(I.lockWalletButton).nth(-1).click(),await t.getByText("Welcome Back").waitFor({state:"visible",timeout:3e4})}import{styleText as wt}from"util";import{expect as Kt}from"@playwright/test";async function R(t,o){let e=t.locator("div[color]").nth(1);if(await e.textContent()===o){console.info(`
|
|
2
|
+
Already on ${o} account. No need to switch.`);return}await e.click();let r=t.locator("div[class='simplebar-content'] > div").locator("> div",{hasText:o});if(!await r.isVisible().catch(()=>!1))throw new Error(`Account "${o}" not found. Make sure the account is onboarded or verify the account name.`);let l=t.locator("div:has-text('Select Wallet')").last();await r.click(),await l.waitFor({state:"detached",timeout:3e4})}async function M({page:t,onboard:o}){if(console.info(wt("yellowBright",`
|
|
3
|
+
Keplr onboarding started...`,{validateStream:!1})),o.length===1){let e=o[0];if(e&&e.mode==="privateKey"){let{privateKey:a,walletName:r,chains:n}=e;await B({page:t,privateKey:a,walletName:r,chains:n,mode:"onboard"})}if(e&&e.mode==="seedPhrase"){let{seedPhrase:a,walletName:r,chains:n}=e;await C({page:t,seedPhrase:a,walletName:r,chains:n,mode:"onboard"})}}if(o.length>1){let e=o[0];if(e&&e.mode==="privateKey"){let{privateKey:i,walletName:u,chains:h}=e;await B({page:t,privateKey:i,walletName:u,chains:h,mode:"onboard"})}if(e&&e.mode==="seedPhrase"){let{seedPhrase:i,walletName:u,chains:h}=e;await C({page:t,seedPhrase:i,walletName:u,chains:h,mode:"onboard"})}let a=o.slice(1);for(let[i,u]of a.entries()){let h=await K(t);if(u.mode==="privateKey"){let{privateKey:x,walletName:f,chains:w}=u;await B({page:h,privateKey:x,walletName:f,chains:w,mode:"add-account-single"})}if(u.mode==="seedPhrase"){let{seedPhrase:x,walletName:f,chains:w}=u;await C({page:h,seedPhrase:x,walletName:f,chains:w,mode:"add-account-single"})}i!==a.length-1&&await t.locator("div",{hasText:"Select Wallet"}).last().locator("../../..").locator("div > svg").click()}await t.locator("div",{hasText:"Select Wallet"}).last().locator("../../..").locator("div > svg").click(),await t.getByRole("link",{name:"Home",exact:!0}).click();let m=t.locator(I.openSidebarMenuButton);await Kt(m).toBeVisible({timeout:3e4});let p=o.at(-1)?.walletName,d=o[0]?.walletName;p&&d&&await R(t,d)}await S(3e3),console.info(wt("greenBright","\u2728 Keplr onboarding completed successfully",{validateStream:!1}))}async function ht(t){let o=t.locator(L.rejectButton);await o.waitFor({state:"visible",timeout:2e4}),await o.click()}async function ft({page:t,currentAccountName:o,newAccountName:e}){let a=dt.parse({currentAccountName:o,newAccountName:e});await t.getByRole("link",{name:"Settings",exact:!0}).click(),await t.locator("div[cursor='pointer']").first().click();let l=t.locator("div",{hasText:a.currentAccountName}).nth(-4);if(!await l.isVisible().catch(()=>!1))throw Error(`Account with name "${a.currentAccountName}" not found`);await l.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 O(t){let o=await N("keplr");await t.locator(U.passwordInput).fill(o),await t.locator(U.unlockButton).click(),await t.locator("div:has-text('Deposit')").last().waitFor({state:"visible",timeout:3e4})}var T=class extends A{page;constructor(o){super(),this.page=o}async onboard(o){await M({page:this.page,onboard:o})}async unlock(){await O(this.page)}async lock(){await ut(this.page)}async renameAccount({currentAccountName:o,newAccountName:e}){await ft({page:this.page,currentAccountName:o,newAccountName:e})}async switchAccount(o){await R(this.page,o)}async getAccountAddress({...o}){return await mt({page:this.page,...o})}async addAccount({chains:o,walletName:e,mode:a="add-account-multiple",...r}){await ct({page:this.page,walletName:e,chains:o,mode:a,...r})}async connectToApp(){await lt(await this.promptPage(this.page.context()))}async confirmTransaction(){await st(await this.promptPage(this.page.context()))}async rejectTransaction(){await ht(await this.promptPage(this.page.context()))}};import xt from"fs";import $t from"path";import{test as Dt,chromium as Vt}from"@playwright/test";import{expect as Lt}from"@playwright/test";async function H(t,o){let e=await t.newPage();return await Lt(async()=>{await e.goto(o),await k(e)}).toPass(),e}async function j(t,o){let e=await o.newPage();for(let{origin:a,localStorage:r}of t){let n=e.mainFrame();await n.goto(a),await n.evaluate(l=>{l.forEach(({name:m,value:p})=>{window.localStorage.setItem(m,p)})},r)}await e.close()}import Rt from"fs/promises";async function gt(t){await Rt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Ot=35e3;async function $(t,o){try{await Promise.race([t.close(),new Promise((e,a)=>setTimeout(()=>a(new Error("Context close timed out")),Ot))])}catch(e){console.warn(`Browser context close did not complete cleanly: ${e.message}`)}try{await gt(o)}catch(e){console.error(`Failed to remove temporary context directory at ${o}. Error:`,e)}}var W,Ba=({slowMo:t=0,profileName:o}={})=>Dt.extend({contextPath:async({browserName:e},a,r)=>{let n=await E(`${e}-${r.testId}`);await a(n)},context:async({context:e,contextPath:a},r)=>{let n=new A,l=y(n.name),m=await F(n.name),p=$t.resolve(l,o??"wallet-data");if(!xt.existsSync(p))throw new Error("\u274C Cache for Keplr wallet data not found. Create it first");xt.cpSync(p,a,{recursive:!0,force:!0});let d=[`--disable-extensions-except=${m}`,`--load-extension=${m}`];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 i=await Vt.launchPersistentContext(a,{headless:!1,args:d,slowMo:process.env.HEADLESS?0:t});await i.grantPermissions(["clipboard-read"]);let{cookies:u,origins:h}=await e.storageState();u&&await i.addCookies(u),h&&h.length>0&&j(h,i);let x=await n.indexUrl();W=i.pages().find(w=>w.url().startsWith(x))||await H(i,x),await k(W);for(let w of i.pages()){let v=w.url();(v.includes("about:blank")||v.includes(n.onboardingPath))&&await w.close()}await W.bringToFront(),await O(W),await r(i),await $(i,a)},keplrPage:async({context:e},a)=>{await a(W)},keplr:async({context:e},a)=>{let r=new T(W);await a(r)}});import{test as Ut}from"@playwright/test";var Na=({slowMo:t,profileName:o}={})=>Ut.extend({workerScopeContents:[async({browser:e},a,r)=>{let n=new A,{context:l,contextPath:m,walletPage:p}=await tt({wallet:n,workerInfo:r,profileName:o,slowMo:t});await l.grantPermissions(["clipboard-read"]);for(let i of l.pages())i.url().includes("about:blank")&&await i.close();let d=new T(p);await d.unlock(),await a({wallet:d,walletPage:p,context:l}),await $(l,m)},{scope:"worker"}]});export{T as Keplr,Ba as keplrFixture,Na as keplrWorkerScopeFixture,tt as workerScopeContext};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { Page, BrowserContext } from '@playwright/test';
|
|
6
6
|
import z from 'zod';
|
|
@@ -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"},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 T=t.locator("div[data-testid^='multichain-account-cell-keyring'][class*='is-selected']"),h=await T.locator("p[class*='multichain-account-cell__account-name']").textContent();h&&await $t({page:t,accountName:n,activeAccountLocator:T,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 T=t.getByTestId("rpc-url-input-test"),h=t.getByRole("button",{name:/Add URL/i});await T.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 Tt({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 At from"fs";import Yt from"path";async function Ct(t){let e=x(t),o=Yt.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(n){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${n.message}`)}}var A=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 Tt({context:e,path:o,locator:"div[data-testid='multichain-page']"})}};import{expect as J}from"@playwright/test";async function X(t,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 A,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 T=`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===T);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(t,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 T=f.getByRole("button",{name:/confirm/i});await b(T).toBeEnabled(),await T.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 A{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(e){await X(this.page,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 A,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 A,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
|
+
import dt from"fs";import Ot from"path";import{chromium as Ht}from"@playwright/test";import Vt from"path";var rt=".wallet-cache",it=".wallet-context";var st="13.33.0",ct="0.13.3",G="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Wt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${ct}/`,Dt=`https://github.com/MetaMask/metamask-extension/releases/download/v${st}/`,he=`${Dt}metamask-chrome-${st}.zip`,xe=`${G}solflare-wallet-extension-v2.19.1.zip`,Be=`${G}petra-wallet-extension-v2.4.8.zip`,ke=`${G}phantom-wallet-extension-v26.10.0.zip`,be=`${G}meteor-wallet-extension-v0.7.0.zip`,Ae=`${Wt}keplr-extension-manifest-v3-v${ct}.zip`;async function v(t){return Vt.resolve(process.cwd(),it,t)}import Ut from"path";function x(t){return Ut.resolve(process.cwd(),rt,t)}import lt from"fs";import $t from"path";async function L(t){try{let e=x(t),o=$t.resolve(e,"extension-path.txt");if(!lt.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let n=lt.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 ze({wallet:t,workerInfo:e,profileName:o,slowMo:n}){let r=await v(e.workerIndex.toString()),i=x(t.name),s=Ot.resolve(i,o??"wallet-data");if(!dt.existsSync(s))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);dt.cpSync(s,r,{recursive:!0,force:!0});let c=await L(t.name),a=await Ht.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 mt from"zod";import{test as Gt}from"@playwright/test";function ut(t,e){t&&(console.warn(`
|
|
2
|
+
\u26A0\uFE0F Skipping test: ${e}`),Gt.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"},U={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 pt({page:t,privateKey:e,accountName:o}){let n=mt.string().min(1,"Account name cannot be an empty string").trim().parse(o),r=mt.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&&ut(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 zt({page:t,accountName:n,activeAccountLocator:A,activeAccountName:h}),await t.locator("button[aria-label='Back']").first().click()}async function zt({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 ft}from"@playwright/test";import F from"zod";var wt=F.object({networkName:F.string().min(1,"Network name cannot be an empty string"),rpcUrl:F.url(),chainId:F.number().or(F.string().includes("0x")),currencySymbol:F.string().toUpperCase().min(1,"Currency symbol cannot be an empty string")});import{expect as Kt}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 Kt(o).toBeVisible(),await o.click())}async function gt({page:t,...e}){let{chainId:o,currencySymbol:n,networkName:r,rpcUrl:i}=wt.parse({...e},{reportInput:!0});await z(t),await t.getByTestId(S.networksButton).click();let c=t.getByTestId(S.networksPageList);await ft(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 N=await y.textContent();throw Error(`RPC error: ${N}`)}await m.fill(`${o}`),await f.fill(n);let P=t.getByRole("button",{name:/save/i});await ft(P).toBeEnabled(),await P.click(),await t.getByTestId(S.headerBackButton).click()}import{expect as yt}from"@playwright/test";function M(t){return new Promise(e=>setTimeout(e,t))}var K={confirmButton:"confirm-footer-button",cancelButton:"confirm-footer-cancel-button"};async function ht(t,e){let o=t.getByTestId(K.confirmButton);await M(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 yt(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 yt(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 jt}from"@playwright/test";async function xt(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 jt.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 Bt(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 Jt}from"@playwright/test";import{errors as qt}from"@playwright/test";async function E(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}var kt={loadingOverlay:"loading-overlay",loadingSpinner:"spinner loading-overlay__spinner"};var Xt=6e4,Qt=async(t,e,o)=>{await E(e);try{await e.locator(`div[class="${t}"]`).waitFor({state:"detached",timeout:o})}catch(n){if(n instanceof qt.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 Qt(kt.loadingSpinner,t,Xt)}catch(e){console.warn("Warning during MetaMask load:",e)}return await M(300),t};async function bt(t){if(await t.getByTestId(U.unlockButton).isVisible().catch(()=>!1)){console.info("\u{1F4A1} Wallet is already locked");return}await z(t);let n=t.getByTestId(S.lockButton);await Jt(n).toBeVisible(),await n.click(),await j(t)}import{styleText as It}from"util";import{expect as D}from"@playwright/test";import At from"fs";import Yt from"path";async function q(t){let e=x(t),o=Yt.resolve(e,"password.txt");try{if(!At.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return At.readFileSync(o,"utf-8")}catch(n){throw new Error(`\u274C Failed to get ${t} password from cache: ${n.message}`)}}import{expect as Zt}from"@playwright/test";async function Tt({context:t,path:e,locator:o}){let n;try{await Zt.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 te(n,o),await n.setViewportSize({width:360,height:592}),n}async function te(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 ee from"path";async function Pt(t){let e=x(t),o=ee.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 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 Pt(this.name)}async promptPage(e){let o=await this.promptUrl();return await Tt({context:e,path:o,locator:"div[data-testid='multichain-page']"})}};import{expect as J}from"@playwright/test";async function X(t,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(It("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(" "),N=t.getByTestId(g.importUsingSecretRecoveryPhraseButton);await c.click(),await N.click();let nt=t.getByTestId(g.secretRecoveryPhraseTextAreaInput);await nt.fill(I[0]),await nt.press("Space");for(let H=1;H<I.length;H++){let at=t.getByTestId(`import-srp__srp-word-${H}`);await at.fill(I[H]),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(),_;await D.poll(async()=>{if(y){let{targetInfos:P}=await y.send("Target.getTargets"),I=P.find(N=>N.url===A);return _=I,!!I}},{timeout:15e3}).toBe(!0),_&&await y?.send("Target.closeTarget",{targetId:_.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(t,e),await M(5e3),console.info(It("greenBright","\u2728 MetaMask onboarding completed successfully",{validateStream:!1}))}import{expect as oe}from"@playwright/test";async function St(t){let e=t.getByTestId(K.cancelButton);await oe(e).toBeEnabled(),await e.click()}import{expect as b}from"@playwright/test";async function vt({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 R=f.getByRole("textbox");await b(R).toBeVisible(),await R.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 Et({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(U.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(U.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 bt(this.page)}async renameAccount({newAccountName:e,currentAccountName:o}){await vt({page:this.page,newAccountName:e,currentAccountName:o})}async addAccount({privateKey:e,accountName:o}){await pt({page:this.page,privateKey:e,accountName:o})}async switchAccount(e){await X(this.page,e)}async switchNetwork({...e}){await Et({page:this.page,...e})}async getAccountAddress(e){return await Bt(this.page,e)}async toggleShowTestnetNetwork(){await W({page:this.page})}async addCustomNetwork({chainId:e,currencySymbol:o,networkName:n,rpcUrl:r}){await gt({page:this.page,chainId:e,currencySymbol:o,networkName:n,rpcUrl:r})}async connectToApp(){await xt(await this.promptPage(this.page.context()))}async confirmTransaction(e){await ht(await this.promptPage(this.page.context()),e)}async rejectTransaction(){await St(await this.promptPage(this.page.context()))}};import Nt from"fs";import ie from"path";import{test as se,chromium as ce}from"@playwright/test";import{Instance as le,Pool as de}from"prool";import{expect as ne}from"@playwright/test";async function et(t,e){let o=await t.newPage();return await ne(async()=>{await o.goto(e),await E(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 ae from"fs/promises";async function _t(t){await ae.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var re=35e3;async function Q(t,e){try{await Promise.race([t.close(),new Promise((o,n)=>setTimeout(()=>n(new Error("Context close timed out")),re))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await _t(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var O,Oa=({slowMo:t=0,profileName:e}={})=>se.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 L(i.name),a=ie.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 ce.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}),O=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 O.locator("img[class='loading-spinner']").waitFor({state:"detached"}),await $(O),await r(l),await Q(l,n)},metamaskPage:async({context:o},n)=>{await n(O)},metamask:async({context:o},n)=>{let r=new V(O);await n(r)},createAnvilNode:async({context:o},n,r)=>{let i=r.workerIndex,s;await n(async c=>{s=de.define({instance:le.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 pe}from"@playwright/test";import{Instance as we,Pool as fe}from"prool";import Lt from"fs";import ue from"path";import{chromium as me}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=ue.resolve(i,e??"wallet-data");if(!Lt.existsSync(s))throw new Error(`Cache for ${n.name} does not exist. Create it first!`);Lt.cpSync(s,r,{recursive:!0,force:!0});let c=await L(n.name),a=await me.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 E(l));for(let m of a.pages())m.url().includes("about:blank")&&await m.close();return{context:a,walletPage:l,contextPath:r}}var ir=({profileName:t,slowMo:e}={})=>pe.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=fe.define({instance:we.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,Oa as metamaskFixture,ir as metamaskWorkerScopeFixture,ze as workerScopeContext};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { BrowserContext, Page } from '@playwright/test';
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
Already on ${o}, no need to switch network.`),"Exit";await e.click();let l=t.locator(
|
|
3
|
-
Switching to the ${o} account aborted. Account is already selected.`);return}await t.locator(u.openSidebarMenuButton).click();let p=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 d of p)if((await d.textContent())?.toLowerCase()===o.toLowerCase()){s=d;break}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function
|
|
4
|
-
`))}async function
|
|
5
|
-
Meteor onboarding started...`,{validateStream:!1}));let c=await
|
|
6
|
-
Retrying search for account. ${y} attempts left`),await
|
|
7
|
-
`),{validateStream:!1}))}await t.locator("button:not([aria-label='Back'],[id^='menu-button']):has-text('Account')").click();let j=t.locator("section[role='dialog']").locator("button:has-text('Close')").first();if(await j.isVisible().then(()=>!0).catch(()=>!1)&&await j.click(),await B({page:t,newAccountName:
|
|
1
|
+
import ot from"fs";import At from"path";import{chromium as kt}from"@playwright/test";import yt from"path";var J=".wallet-cache",Y=".wallet-context";var Q="13.33.0",Z="0.13.3",W="https://github.com/amaify/chainwright/releases/download/v0.1.0/",xt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${Z}/`,gt=`https://github.com/MetaMask/metamask-extension/releases/download/v${Q}/`,$t=`${gt}metamask-chrome-${Q}.zip`,Vt=`${W}solflare-wallet-extension-v2.19.1.zip`,Kt=`${W}petra-wallet-extension-v2.4.8.zip`,Ht=`${W}phantom-wallet-extension-v26.10.0.zip`,zt=`${W}meteor-wallet-extension-v0.7.0.zip`,jt=`${xt}keplr-extension-manifest-v3-v${Z}.zip`;async function v(t){return yt.resolve(process.cwd(),Y,t)}import bt from"path";function h(t){return bt.resolve(process.cwd(),J,t)}import tt from"fs";import Pt from"path";async function _(t){try{let o=h(t),a=Pt.resolve(o,"extension-path.txt");if(!tt.existsSync(a))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let e=tt.readFileSync(a,"utf-8").trim();if(!e)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return e}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function et({wallet:t,workerInfo:o,profileName:a,slowMo:e}){let r=await v(o.workerIndex.toString()),c=h(t.name),w=At.resolve(c,a??"wallet-data");if(!ot.existsSync(w))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);ot.cpSync(w,r,{recursive:!0,force:!0});let l=await _(t.name),p=await kt.launchPersistentContext(r,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:e}),s=await t.indexUrl(),d=p.pages()[0];return d||(d=await p.newPage()),await d.goto(s),{context:p,walletPage:d,contextPath:r}}var u={openSidebarMenuButton:"button[aria-label='open sidebar']",addWalletButton:"button:has-text('Add Wallet')",settingsButton:"button:has-text('Settings')",settingsMenuBackButton:"button[aria-label='Back']"};var m={importExistingWalletButton:'button:has-text("Import an existing wallet")',switchNetworkButton:"button[id^='menu-button']",privateKeyButton:"button:has-text('Private Key')",secretPhraseButton:"button:has-text('Secret Phrase')",findMyAccountButton:"button:has-text('Find my account')"};async function N(t,o,a){let e=t.locator(m.switchNetworkButton).last();await e.scrollIntoViewIfNeeded();let r=await e.textContent(),c=o.split("net")[0]?.toLowerCase()??"";if(r?.toLowerCase()===c)return console.info(`
|
|
2
|
+
Already on ${o}, no need to switch network.`),"Exit";await e.click();let l=t.locator(a).last().locator(`> button:has-text('${o}')`);await l.click(),await t.locator("div > h2:has-text('Meteor Community')").isVisible().catch(()=>!1)&&await l.click()}async function B({page:t,newAccountName:o}){await t.locator(u.openSidebarMenuButton).click(),await t.locator("div:has(> h2):has(> svg)").click();let r=t.locator("input[placeholder='Ex. My Meteor Wallet']"),c=t.locator("button[type='submit']:has-text('Update')");await r.fill(o),await c.click(),await t.locator("div[id='root'] button[aria-label='Close']").click()}async function L({page:t,accountName:o,network:a,...e}){await t.locator(u.openSidebarMenuButton).click(),await t.locator(u.addWalletButton).click(),await N(t,a,"section[role='dialog'] div[role='menu']"),await t.locator(m.importExistingWalletButton).click();let l=t.locator('button:has-text("Continue")');e.mode==="secretPhrase"&&(await t.locator(m.secretPhraseButton).click(),await l.scrollIntoViewIfNeeded(),await l.click(),await t.locator("textarea:not([disabled])").fill(e.secretPhrase)),e.mode==="privateKey"&&(await t.locator(m.privateKeyButton).click(),await l.scrollIntoViewIfNeeded(),await l.click(),await t.locator("textarea:not([disabled])").fill(e.privateKey)),await t.locator(m.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 B({page:t,newAccountName:o})}var P={approveButton:"button:has-text('Approve')",connectButton:"button:has-text('Connect')",cancelButton:"button:has-text('Cancel')",logoutButton:"button:has-text('Logout')"};import at from"fs";import Bt from"path";async function I(t){let o=h(t),a=Bt.resolve(o,"password.txt");try{if(!at.existsSync(a))throw new Error("\u274C password.txt not found. Run setup script first.");return at.readFileSync(a,"utf-8")}catch(e){throw new Error(`\u274C Failed to get ${t} password from cache: ${e.message}`)}}async function f(t){let o=await I("meteor"),a=t.locator("input[placeholder='Enter Password']"),e=t.locator('button:has-text("Unlock")');if(!await a.waitFor({state:"visible",timeout:5e3}).then(()=>!0).catch(()=>!1)){console.info("\u{1F4A1} Wallet is already unlocked");return}await a.fill(o),await e.click()}async function rt(t){await f(t),await t.locator(P.logoutButton).click()}async function nt(t){await f(t),await t.locator(P.approveButton).click(),await t.locator("h2:has-text('Executing Transaction')").waitFor({state:"attached"}),await t.waitForEvent("close",{timeout:15e3})}async function C(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
|
+
Switching to the ${o} account aborted. Account is already selected.`);return}await t.locator(u.openSidebarMenuButton).click();let p=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 d of p)if((await d.textContent())?.toLowerCase()===o.toLowerCase()){s=d;break}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function it(t,o){await f(t),o&&await C(t,o);let a=t.getByRole("heading",{name:"Connect Request",exact:!0});await Promise.all([t.locator(P.connectButton).click(),a.waitFor({state:"detached",timeout:3e4})])}async function ct(t){let e=t.locator("div:has(button[type='button'][aria-label='open sidebar'])").nth(-2).locator("div:has(div > h2)").locator("div > svg"),r=t.locator(".chakra-toast").last();await e.click(),await r.waitFor({state:"visible",timeout:5e3});let c=await t.evaluate(async()=>await navigator.clipboard.readText());return await r.waitFor({state:"hidden",timeout:5e3}),c}async function st(t){await t.locator(u.openSidebarMenuButton).click(),await t.locator("button:has-text('Lock Wallet')").click()}import{styleText as R}from"util";function M(t){return new Promise(o=>setTimeout(o,t))}import{expect as Ct}from"@playwright/test";async function lt({context:t,path:o,locator:a}){let e;try{await Ct.poll(async()=>(e=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(o)),!!e),{timeout:3e4}).toBe(!0)}catch{let r=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(r)}`)}if(!e)throw new Error(`Popup page with path ${o} not found in context.`);return await St(e,a),await e.setViewportSize({width:360,height:592}),e}async function St(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 pt from"fs";import Et from"path";async function ut(t){let o=h(t),a=Et.resolve(o,"extension-id.txt");try{if(!pt.existsSync(a))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return pt.readFileSync(a,"utf-8")}catch(e){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${e.message}`)}}var g=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 ut(this.name)}async promptPage(o){let a=await this.promptUrl();return await lt({context:o,path:a,locator:"div[id='root']"})}};async function S(t){await t.locator(u.openSidebarMenuButton).click(),await t.locator(u.settingsButton).click()}async function F(t,o){if(await S(t),await N(t,o,"div[role='menu']")==="Exit"){let c=t.locator(u.settingsMenuBackButton);await c.scrollIntoViewIfNeeded(),await c.click();return}let e=t.locator("p:has-text('Available Balance')");if(await M(1e3),!await e.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
|
+
`))}async function O({page:t,network:o,accountName:a,additionalAccounts:e,...r}){console.info(R("yellowBright",`
|
|
5
|
+
Meteor onboarding started...`,{validateStream:!1}));let c=await I("meteor"),l=await new g().indexUrl();await t.goto(l);let p=t.locator(m.switchNetworkButton),s=await p.textContent(),d=o.split("net")[0]?.toLowerCase()??"";s?.toLowerCase().includes(d)||(await p.click(),await t.locator("div[role='menu']").locator(`> button:has-text('${o}')`).click());let b=t.locator("input[placeholder='Enter Password']"),k=t.locator("input[placeholder='Confirm Password']"),K=t.locator("label.chakra-checkbox .chakra-checkbox__control"),x=t.locator('button:has-text("Continue")');await b.fill(c),await k.fill(c),await K.click(),await x.click(),await t.locator(m.importExistingWalletButton).click(),r.mode==="secretPhrase"&&(await t.locator(m.secretPhraseButton).click(),await x.scrollIntoViewIfNeeded(),await x.click(),await t.locator("textarea:not([disabled])").fill(r.secretPhrase)),r.mode==="privateKey"&&(await t.locator(m.privateKeyButton).click(),await x.scrollIntoViewIfNeeded(),await x.click(),await t.locator("textarea:not([disabled])").fill(r.privateKey));let H=t.locator(m.findMyAccountButton);await H.click();let z=t.locator("button[type='submit'][data-loading]");if(await z.waitFor({state:"detached",timeout:25e3}),await t.getByRole("status").locator("div[id='toast-1-title']:has-text('No Account Found')").isVisible().catch(()=>!1)){let y=5,A=!1;for(;y>0;){if(console.info(`
|
|
6
|
+
Retrying search for account. ${y} attempts left`),await M(15e3),await H.click(),await z.waitFor({state:"detached",timeout:2e4}),await t.locator("div:has-text('Import Your Account')").nth(-2).locator("button").isVisible().catch(()=>!1)){A=!0;break}y-=1}if(!A)throw Error(R("redBright",["No Account Found","Account associated with the private key not found. Please make sure you are trying to import an account on the correct network(Mainnet/Testnet)."].join(`
|
|
7
|
+
`),{validateStream:!1}))}await t.locator("button:not([aria-label='Back'],[id^='menu-button']):has-text('Account')").click();let j=t.locator("section[role='dialog']").locator("button:has-text('Close')").first();if(await j.isVisible().then(()=>!0).catch(()=>!1)&&await j.click(),await B({page:t,newAccountName:a}),e&&e.length>0){for(let{accountName:q,network:G,...ht}of e)await L({page:t,accountName:q,network:G,...ht});await S(t);let y=t.locator(m.switchNetworkButton).last();await y.scrollIntoViewIfNeeded();let A=await y.textContent(),X=o.split("net")[0]?.toLowerCase()??"";A?.toLowerCase()!==X&&await F(t,o),await C(t,a)}await M(3e3),console.info(R("greenBright","\u2728 Meteor onboarding completed successfully"))}async function mt(t){await f(t),await t.locator(P.cancelButton).click()}var E=class extends g{page;constructor(o){super(),this.page=o}async onboard({network:o,accountName:a,additionalAccounts:e,...r}){await O({page:this.page,network:o,accountName:a,additionalAccounts:e,...r})}async unlock(){await f(this.page)}async lock(){await st(this.page)}async renameAccount({newAccountName:o}){await B({page:this.page,newAccountName:o})}async switchNetwork(o){await F(this.page,o)}async switchAccount(o){await C(this.page,o)}async getAccountAddress(){return await ct(this.page)}async addAccount({accountName:o,network:a,...e}){await L({page:this.page,accountName:o,network:a,...e})}async openSettings(){await S(this.page)}async connectToApp(o){await it(await this.promptPage(this.page.context()),o)}async confirmDisconnect(){await rt(await this.promptPage(this.page.context()))}async confirmTransaction(){await nt(await this.promptPage(this.page.context()))}async rejectTransaction(){await mt(await this.promptPage(this.page.context()))}};import dt from"fs";import Wt from"path";import{test as _t,chromium as Nt}from"@playwright/test";import{expect as vt}from"@playwright/test";async function U(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function $(t,o){let a=await t.newPage();return await vt(async()=>{await a.goto(o),await U(a)}).toPass(),a}async function V(t,o){let a=await o.newPage();for(let{origin:e,localStorage:r}of t){let c=a.mainFrame();await c.goto(e),await c.evaluate(w=>{w.forEach(({name:l,value:p})=>{window.localStorage.setItem(l,p)})},r)}await a.close()}import Mt from"fs/promises";async function wt(t){await Mt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Tt=35e3;async function D(t,o){try{await Promise.race([t.close(),new Promise((a,e)=>setTimeout(()=>e(new Error("Context close timed out")),Tt))])}catch(a){console.warn(`Browser context close did not complete cleanly: ${a.message}`)}try{await wt(o)}catch(a){console.error(`Failed to remove temporary context directory at ${o}. Error:`,a)}}var T,Da=({slowMo:t=0,profileName:o}={})=>_t.extend({contextPath:async({browserName:a},e,r)=>{let c=await v(`${a}-${r.testId}`);await e(c)},context:async({context:a,contextPath:e},r)=>{let c=new g,w=h(c.name),l=await _(c.name),p=Wt.resolve(w,o??"wallet-data");if(!dt.existsSync(p))throw new Error("\u274C Cache for Meteor wallet data not found. Create it first");dt.cpSync(p,e,{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 s=await Nt.launchPersistentContext(e,{headless:!1,args:[`--disable-extensions-except=${l}`,`--load-extension=${l}`],slowMo:process.env.HEADLESS?0:t});await s.grantPermissions(["clipboard-read"]);let{cookies:d,origins:b}=await a.storageState();d&&await s.addCookies(d),b&&b.length>0&&V(b,s);let k=await c.indexUrl();T=s.pages().find(x=>x.url().startsWith(k))||await $(s,k);for(let x of s.pages())x.url().includes("about:blank")&&await x.close();await T.bringToFront(),await f(T),await r(s),await D(s,e)},meteorPage:async({context:a},e)=>{await e(T)},meteor:async({context:a},e)=>{let r=new E(T);await e(r)}});import{test as Lt}from"@playwright/test";var za=({slowMo:t,profileName:o}={})=>Lt.extend({workerScopeContents:[async({browser:a},e,r)=>{let{context:c,contextPath:w,walletPage:l}=await et({workerInfo:r,profileName:o,slowMo:t,wallet:new g});await c.grantPermissions(["clipboard-read"]);for(let s of c.pages())s.url().includes("about:blank")&&await s.close();let p=new E(l);await p.unlock(),await e({wallet:p,walletPage:l,context:c}),await D(c,w)},{scope:"worker"}]});export{E as Meteor,Da as meteorFixture,za as meteorWorkerScopeFixture,et as workerScopeContext};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { Page, BrowserContext } from '@playwright/test';
|
|
6
6
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
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){let d=(await p.textContent())?.split("0x")[0]?.split("...")[0];if(o.toLowerCase().includes(d?.toLowerCase()??"")){s=p;break}}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function
|
|
3
|
-
Petra onboarding started...`,{validateStream:!1}));let
|
|
1
|
+
import q from"fs";import Bt from"path";import{chromium as bt}from"@playwright/test";import yt from"path";var G=".wallet-cache",X=".wallet-context";var Z="13.33.0",J="0.13.3",L="https://github.com/amaify/chainwright/releases/download/v0.1.0/",xt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${J}/`,ht=`https://github.com/MetaMask/metamask-extension/releases/download/v${Z}/`,Nt=`${ht}metamask-chrome-${Z}.zip`,$t=`${L}solflare-wallet-extension-v2.19.1.zip`,Kt=`${L}petra-wallet-extension-v2.4.8.zip`,Vt=`${L}phantom-wallet-extension-v26.10.0.zip`,zt=`${L}meteor-wallet-extension-v0.7.0.zip`,Ht=`${xt}keplr-extension-manifest-v3-v${J}.zip`;async function W(t){return yt.resolve(process.cwd(),X,t)}import gt from"path";function x(t){return gt.resolve(process.cwd(),G,t)}import Y from"fs";import Pt from"path";async function R(t){try{let o=x(t),e=Pt.resolve(o,"extension-path.txt");if(!Y.existsSync(e))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=Y.readFileSync(e,"utf-8").trim();if(!a)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return a}catch(o){throw new Error(`\u274C Failed to get ${t} extension path: ${o.message}`)}}async function Q({wallet:t,workerInfo:o,profileName:e,slowMo:a}){let r=await W(o.workerIndex.toString()),c=x(t.name),s=Bt.resolve(c,e??"wallet-data");if(!q.existsSync(s))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);q.cpSync(s,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}),d=await t.indexUrl(),l=m.pages()[0];return l||(l=await m.newPage()),await l.goto(d),{context:m,walletPage:l,contextPath:r}}var u={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']"},K={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 At from"zod";async function S({page:t,newAccountName:o}){let e=At.string().min(1,"Account name cannot be an empty string").parse(o);await t.locator(u.settingsMenu).click(),await _(t.getByText("Settings").first()).toBeVisible();let r=t.locator(h.editAccountButton);await _(r).toBeVisible(),await r.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(u.backButton).click(),await Promise.allSettled([t.locator(u.depositButton).waitFor({state:"visible",timeout:2e4}),t.locator(u.sendButton).waitFor({state:"visible",timeout:2e4})])}async function O({page:t,accountName:o,mode:e,...a}){if(await t.locator(h.accountOptionsMenuButton).first().click(),await t.getByRole("dialog").locator(h.addAccountButton).click(),e==="privateKey"){let p="privateKey"in a?a.privateKey:"";if(await t.locator(h.addAccountWithPrivateKeyButton).click(),await t.locator(w.privateKeyInput).fill(p),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 ${o} already exists in wallet`);await S({page:t,newAccountName:o})}if(e==="mnemonic"){let m=("mnemonicPhrase"in a?a.mnemonicPhrase:"").split(" ");await t.locator(h.addAccountWithMnemonicButton).click();for(let[A,y]of m.entries())await t.locator(`input[name="mnemonic-${String.fromCharCode(97+A)}"]`).fill(y);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 ${o} already exists in wallet`);await S({page:t,newAccountName:o})}}function D(t){return new Promise(o=>setTimeout(o,t))}var C={approveButton:'button:has-text("Approve")',cancelButton:'button:has-text("Cancel")'};var kt=/^[A-Z0-9]+(?:_[A-Z0-9]+)+$/;function tt(t){return kt.test(t)?t.toLowerCase().replace(/_/g," ").replace(/\b[a-z]/g,o=>o.toUpperCase()):t}async function St(t,o){for(;;){let a=o();if(a||t.isClosed())break;try{let r=t.locator("div:has(> h2:has-text('Simulation error'))");if(await r.isVisible().catch(()=>!1)){let s=await r.locator("p").textContent();throw new Error(`[Confirm Transaction Error]: ${tt(s||"Unexpected error!")}`)}}catch(r){if(t.isClosed())break;throw r instanceof Error?r:new Error(`[Confirm Transaction Error]: ${r}`)}if(a||t.isClosed())break;await D(300)}}async function ot(t){let o=!1;St(t,()=>o).catch(async r=>{t.isClosed()||console.error(r.message)}),await t.locator(C.approveButton).click(),o=!0}import{expect as Ct}from"@playwright/test";async function E(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
|
+
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){let d=(await p.textContent())?.split("0x")[0]?.split("...")[0];if(o.toLowerCase().includes(d?.toLowerCase()??"")){s=p;break}}if(!s)throw new Error(`Account with name "${o}" not found.`);await s.click()}async function et(t,o){o&&await E(t,o);let e=t.locator(C.approveButton);await Ct(e).toBeEnabled({timeout:2e4}),await e.click()}async function at(t){return await t.getByRole("button",{name:"Copy Address",exact:!0}).click(),await t.evaluate(async()=>await navigator.clipboard.readText())}import{expect as rt}from"@playwright/test";async function nt(t){let o=t.locator(u.settingsMenu);await rt(o).toBeVisible(),await o.click(),await rt(t.getByText("Settings").first()).toBeVisible()}async function it(t){await nt(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 mt}from"util";import{expect as B}from"@playwright/test";async function I(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}import ct from"fs";import Et from"path";async function U(t){let o=x(t),e=Et.resolve(o,"password.txt");try{if(!ct.existsSync(e))throw new Error("\u274C password.txt not found. Run setup script first.");return ct.readFileSync(e,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Tt}from"@playwright/test";async function st({context:t,path:o,locator:e}){let a;try{await Tt.poll(async()=>(a=t.pages().filter(r=>r.url().startsWith("chrome-extension://")).find(r=>r.url().match(o)),!!a),{timeout:3e4}).toBe(!0)}catch{let r=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(r)}`)}if(!a)throw new Error(`Popup page with path ${o} not found in context.`);return await vt(a,e),await a.setViewportSize({width:360,height:592}),a}async function vt(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 lt from"fs";import Wt from"path";async function pt(t){let o=x(t),e=Wt.resolve(o,"extension-id.txt");try{if(!lt.existsSync(e))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return lt.readFileSync(e,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.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 pt(this.name)}async promptPage(o){let e=await this.promptUrl();return await st({context:o,path:e,locator:"div[id='prompt']"})}};async function N(t,o){await t.locator(u.settingsMenu).click(),await t.locator(K.networkSection).click(),await t.locator(`div:has(> span:has-text("${o}"))`).first().click();let c=t.locator(K.backButton);await c.click(),await c.click()}var T=3e4;async function z({page:t,network:o,...e}){console.info(mt("yellowBright",`
|
|
3
|
+
Petra onboarding started...`,{validateStream:!1}));let a=new g,r=await U("petra"),c=t.locator(w.createWalletButton),s=t.locator(w.importWalletButton),p=t.locator(w.createNewPasswordInput),m=t.locator(w.confirmNewPasswordInput),d=t.locator(w.confirmPasswordCheckbox),l=t.locator(w.continueButton),b=t.locator(w.getStartedButton),P=t.locator(w.onboardingCompleteText);if(e.mode==="create"){let f=t.locator(w.createSeedPhraseButton);await c.click(),await f.click(),await p.fill(r),await m.fill(r),await d.click(),await l.click(),await t.locator(w.skipCopyRecoveryPhraseButton).click(),await b.click(),await B(P).toBeVisible({timeout:25e3}),await t.goto(await a.indexUrl()),await B(t.locator(u.depositButton)).toBeVisible({timeout:T}),await B(t.locator(u.sendButton)).toBeVisible({timeout:T})}if(e.mode==="importPrivateKey"){let{privateKey:f}=e,A=t.locator(w.importUsingPrivateKeyButton),y=t.locator(w.privateKeyInput),k=t.locator(w.importButton);await s.click(),await A.click(),await y.fill(f),await k.click(),await p.fill(r),await m.fill(r),await d.click(),await l.click(),await b.click(),await B(P).toBeVisible({timeout:25e3}),await t.goto(await a.indexUrl()),await I(t),await B(t.locator(u.depositButton)).toBeVisible({timeout:T}),await B(t.locator(u.sendButton)).toBeVisible({timeout:T})}if(e.mode==="importMnemonic"){let{secretRecoveryPhrase:f}=e,A=t.locator(w.importUsingMnemonicButton);await s.click(),await A.click();for(let[y,k]of f.split(" ").entries())await t.locator(`input[name="mnemonic-${String.fromCharCode(97+y)}"]`).fill(k);await l.click(),await p.fill(r),await m.fill(r),await d.click(),await l.click(),await b.click(),await B(P).toBeVisible({timeout:25e3}),await t.goto(await a.indexUrl()),await B(t.locator(u.depositButton)).toBeVisible({timeout:T}),await B(t.locator(u.sendButton)).toBeVisible({timeout:T})}if(await S({page:t,newAccountName:e.accountName}),e.additionalAccounts&&e.additionalAccounts.length>0){for(let{...f}of e.additionalAccounts)await O({page:t,...f});await E(t,e.accountName)}await N(t,o),await D(1500),console.info(mt("greenBright","\u2728 Petra onboarding completed successfully",{validateStream:!1}))}import{expect as _t}from"@playwright/test";async function ut(t){let o=t.locator(C.cancelButton);await _t(o).toBeEnabled(),await o.click()}import{expect as wt}from"@playwright/test";async function M(t){let o=await U("petra"),e=t.locator(V.passwordInput);if(!await e.isVisible().then(()=>!0).catch(()=>!1)){console.info("\u{1F4A1} Wallet is already unlocked");return}await wt(e).toBeVisible({timeout:15e3}),await e.fill(o);let r=t.locator(V.unlockButton);await wt(r).toBeEnabled(),await r.click(),await Promise.allSettled([t.locator(u.sendButton).waitFor({state:"visible",timeout:2e4}),t.locator(u.receiveButton).waitFor({state:"visible",timeout:2e4})])}var v=class extends g{page;constructor(o){super(),this.page=o}async onboard(o){await z({page:this.page,...o})}async unlock(){await M(this.page)}async lock(){await it(this.page)}async renameAccount({newAccountName:o}){await S({page:this.page,newAccountName:o})}async switchNetwork(o){await N(this.page,o)}async switchAccount(o){await E(this.page,o)}async getAccountAddress(){return await at(this.page)}async addAccount({accountName:o,...e}){await O({page:this.page,accountName:o,...e})}async connectToApp(o){await et(await this.promptPage(this.page.context()),o)}async confirmTransaction(){await ot(await this.promptPage(this.page.context()))}async rejectTransaction(){await ut(await this.promptPage(this.page.context()))}};import ft from"fs";import Lt from"path";import{test as Rt,chromium as Ot}from"@playwright/test";import{expect as It}from"@playwright/test";async function H(t,o){let e=await t.newPage();return await It(async()=>{await e.goto(o),await I(e)}).toPass(),e}async function j(t,o){let e=await o.newPage();for(let{origin:a,localStorage:r}of t){let c=e.mainFrame();await c.goto(a),await c.evaluate(s=>{s.forEach(({name:p,value:m})=>{window.localStorage.setItem(p,m)})},r)}await e.close()}import Mt from"fs/promises";async function dt(t){await Mt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Ft=35e3;async function $(t,o){try{await Promise.race([t.close(),new Promise((e,a)=>setTimeout(()=>a(new Error("Context close timed out")),Ft))])}catch(e){console.warn(`Browser context close did not complete cleanly: ${e.message}`)}try{await dt(o)}catch(e){console.error(`Failed to remove temporary context directory at ${o}. Error:`,e)}}var F,Ma=({slowMo:t=0,profileName:o}={})=>Rt.extend({contextPath:async({browserName:e},a,r)=>{let c=await W(`${e}-${r.testId}`);await a(c)},context:async({context:e,contextPath:a},r)=>{let c=new g,s=x(c.name),p=await R(c.name),m=Lt.resolve(s,o??"wallet-data");if(!ft.existsSync(m))throw new Error("\u274C Cache for Petra wallet data not found. Create it first");ft.cpSync(m,a,{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 Ot.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${p}`],slowMo:process.env.HEADLESS?0:t});await l.grantPermissions(["clipboard-read"]);let{cookies:b,origins:P}=await e.storageState();b&&await l.addCookies(b),P&&P.length>0&&j(P,l);let f=await c.indexUrl();F=l.pages().find(y=>y.url().startsWith(f))||await H(l,f);for(let y of l.pages()){let k=y.url();(k.includes("about:blank")||k.includes(c.onboardingPath))&&await y.close()}await F.bringToFront(),await M(F),await r(l),await $(l,a)},petraPage:async({context:e},a)=>{await a(F)},petra:async({context:e},a)=>{let r=new v(F);await a(r)}});import{test as Dt}from"@playwright/test";var $a=({slowMo:t,profileName:o}={})=>Dt.extend({workerScopeContents:[async({browser:e},a,r)=>{let c=new g,{context:s,contextPath:p,walletPage:m}=await Q({wallet:c,workerInfo:r,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 v(m);await d.unlock(),await a({wallet:d,walletPage:m,context:s}),await $(s,p)},{scope:"worker"}]});export{v as Petra,Ma as petraFixture,$a as petraWorkerScopeFixture,Q as workerScopeContext};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { BrowserContext, Page } from '@playwright/test';
|
|
6
6
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import at from"fs";import At from"path";import{chromium as bt}from"@playwright/test";import Pt from"path";var tt=".wallet-cache",et=".wallet-context";var Z="13.33.0",_="https://github.com/amaify/chainwright/releases/download/v0.1.0/",zt=`https://github.com/MetaMask/metamask-extension/releases/download/v${Z}/metamask-chrome-${Z}.zip`,jt=`${_}solflare-wallet-extension-v2.19.1.zip`,Xt=`${_}petra-wallet-extension-v2.4.8.zip`,Jt=`${_}phantom-wallet-extension-v26.10.0.zip`,qt=`${_}meteor-wallet-extension-v0.7.0.zip`,Qt=`${_}keplr-wallet-extension-v0.13.3.zip`;async function T(t){return Pt.resolve(process.cwd(),et,t)}import kt from"path";function x(t){return kt.resolve(process.cwd(),tt,t)}import ot from"fs";import Ct from"path";async function I(t){try{let e=x(t),o=Ct.resolve(e,"extension-path.txt");if(!ot.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=ot.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=At.resolve(r,o??"wallet-data");if(!at.existsSync(u))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);at.cpSync(u,n,{recursive:!0,force:!0});let i=await I(t.name),m=await bt.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"},nt={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 R({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 rt(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 It}from"@playwright/test";import Tt from"zod";async function v(t,e){let o=Tt.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 it(t,e){e&&await v(t,e);let o=t.getByTestId(S.confirmButton);await It(o).toBeEnabled({timeout:15e3}),await o.click()}import St from"zod";var vt=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");async function ct({page:t,accountName:e,chain:o}){let a=St.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(`${vt(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 st(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click(),await t.getByTestId(B.lockWalletButton).click()}import{styleText as wt}from"util";import{expect as _t}from"@playwright/test";function M(t){return new Promise(e=>setTimeout(e,t))}import lt from"fs";import Et from"path";async function D(t){let e=x(t),o=Et.resolve(e,"password.txt");try{if(!lt.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return lt.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Wt}from"@playwright/test";async function ut({context:t,path:e,locator:o}){let a;try{await Wt.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 Ft(a,o),await a.setViewportSize({width:360,height:592}),a}async function Ft(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 mt from"fs";import Nt from"path";async function pt(t){let e=x(t),o=Nt.resolve(e,"extension-id.txt");try{if(!mt.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return mt.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var P=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 pt(this.name)}async promptPage(e){let o=await this.promptUrl();return await ut({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 M(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(nt.accountProfileContainer).locator("div[data-testid^='manage-accounts-sortable'] div > p").all(),i=null;for(let d of u)if((await d.textContent())?.toLowerCase()===e.toLowerCase()){i=d;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 nt from"fs";import St from"path";import{chromium as It}from"@playwright/test";import At from"path";var Z=".wallet-cache",tt=".wallet-context";var et="13.33.0",ot="0.13.3",O="https://github.com/amaify/chainwright/releases/download/v0.1.0/",kt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${ot}/`,Ct=`https://github.com/MetaMask/metamask-extension/releases/download/v${et}/`,Jt=`${Ct}metamask-chrome-${et}.zip`,qt=`${O}solflare-wallet-extension-v2.19.1.zip`,Qt=`${O}petra-wallet-extension-v2.4.8.zip`,Yt=`${O}phantom-wallet-extension-v26.10.0.zip`,Zt=`${O}meteor-wallet-extension-v0.7.0.zip`,te=`${kt}keplr-extension-manifest-v3-v${ot}.zip`;async function T(t){return At.resolve(process.cwd(),tt,t)}import bt from"path";function x(t){return bt.resolve(process.cwd(),Z,t)}import at from"fs";import Tt from"path";async function S(t){try{let e=x(t),o=Tt.resolve(e,"extension-path.txt");if(!at.existsSync(o))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let a=at.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 ke({wallet:t,workerInfo:e,profileName:o,slowMo:a}){let n=await T(e.workerIndex.toString()),r=x(t.name),u=St.resolve(r,o??"wallet-data");if(!nt.existsSync(u))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);nt.cpSync(u,n,{recursive:!0,force:!0});let i=await S(t.name),m=await It.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"},rt={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 R({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 I={confirmButton:"primary-button",cancelButton:"secondary-button"};async function it(t){let e=t.getByTestId(I.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 Et}from"@playwright/test";import vt from"zod";async function v(t,e){let o=vt.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 ct(t,e){e&&await v(t,e);let o=t.getByTestId(I.confirmButton);await Et(o).toBeEnabled({timeout:15e3}),await o.click()}import Wt from"zod";var _t=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");async function st({page:t,accountName:e,chain:o}){let a=Wt.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 d=new RegExp(`${_t(o.network)}`,"i");await t.getByRole("button",{name:d}).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 lt(t){await t.getByTestId(g.openMenuButton).click(),await t.getByTestId(g.settingsButton).click(),await t.getByTestId(B.lockWalletButton).click()}import{styleText as wt}from"util";import{expect as Ot}from"@playwright/test";function F(t){return new Promise(e=>setTimeout(e,t))}import ut from"fs";import Nt from"path";async function D(t){let e=x(t),o=Nt.resolve(e,"password.txt");try{if(!ut.existsSync(o))throw new Error("\u274C password.txt not found. Run setup script first.");return ut.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} password from cache: ${a.message}`)}}import{expect as Ft}from"@playwright/test";async function mt({context:t,path:e,locator:o}){let a;try{await Ft.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 Lt(a,o),await a.setViewportSize({width:360,height:592}),a}async function Lt(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 pt from"fs";import Mt from"path";async function dt(t){let e=x(t),o=Mt.resolve(e,"extension-id.txt");try{if(!pt.existsSync(o))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return pt.readFileSync(o,"utf-8")}catch(a){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${a.message}`)}}var P=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 dt(this.name)}async promptPage(e){let o=await this.promptUrl();return await mt({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 F(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(rt.accountProfileContainer).locator("div[data-testid^='manage-accounts-sortable'] div > p").all(),i=null;for(let w of u)if((await w.textContent())?.toLowerCase()===e.toLowerCase()){i=w;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 G({page:t,additionalAccounts:e,...o}){console.info(wt("yellowBright",`
|
|
3
|
-
Phantom onboarding started...`,{validateStream:!1}));let a=await D("phantom");if(o.mode==="create"){await t.locator(p.createNewWalletButton).click(),await t.getByTestId(p.createSeedPhraseWalletButton).click();let
|
|
3
|
+
Phantom onboarding started...`,{validateStream:!1}));let a=await D("phantom");if(o.mode==="create"){await t.locator(p.createNewWalletButton).click(),await t.getByTestId(p.createSeedPhraseWalletButton).click();let w=t.getByTestId(p.passwordInput),f=t.getByTestId(p.passwordConfirmInput),A=t.getByTestId(p.termsCheckBox),k=t.locator(p.continueButton);await w.fill(a),await f.fill(a),await A.click(),await k.click(),await k.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.getByTestId(p.recoveryPhraseSavedCheckbox).click(),await k.click(),await F(1e3),await k.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[N,Y]of Object.entries(y))await t.getByTestId(`${p.recoveryPhraseInput}-${N}`).fill(Y);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),M=t.getByTestId(p.passwordConfirmInput),X=t.getByTestId(p.termsCheckBox);await b.fill(a),await M.fill(a),await X.click(),await C.click(),await C.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.getByRole("textbox",{name:"Username @ Clear",exact:!0}).waitFor({state:"attached",timeout:5e3}).then(async()=>{await t.getByRole("button",{name:"Continue",exact:!0}).click()}).catch(()=>{}),await t.locator(p.getStartedButton).last().click()}if(o.mode==="private key"){await t.locator(p.IAlreadyHaveAWalletButton).click();let{privateKey:y,chain:w,accountName:f}=o;await t.locator(p.importPrivateKeyButton).click();let k=t.locator("span[id='button--listbox-input--1']"),C=await k.textContent(),b=t.locator("input[name='name']"),M=t.locator("textarea[name='privateKey']");C!==w&&(await k.click(),await t.locator("ul[id='listbox--listbox-input--1']").locator(`li[data-label='${w}']`).click()),await b.fill(f),await M.fill(y),await t.locator("button:has-text('Import')").click();let J=t.getByTestId(p.passwordInput),q=t.getByTestId(p.passwordConfirmInput),Q=t.getByTestId(p.termsCheckBox);await J.fill(a),await q.fill(a),await Q.click();let N=t.locator(p.continueButton);await N.click(),await N.locator("> div > svg").waitFor({state:"detached",timeout:3e4}),await t.locator(p.getStartedButton).last().click()}let n=await t.context().newPage(),r=await new P().indexUrl();await n.goto(r);let i=await t.context().browser()?.newBrowserCDPSession(),m;await Ot.poll(async()=>{if(i){let{targetInfos:d}=await i.send("Target.getTargets"),w=d.filter(f=>f.title==="Phantom Wallet").find(f=>!f.attached&&f.url===r);return m=w,!!w}},{timeout:2e4}).toBe(!0),m&&await i?.send("Target.closeTarget",{targetId:m.targetId});let l=await n.getByTestId("home-header-account-name").textContent();if(!l)throw new Error("Cannot find initial account name");if(o.mode==="create"||o.mode==="recovery phrase"){let{accountName:d}=o;await $({page:n,newAccountName:d,currentAccountName:l})}if(e&&e.length>0){let d=!1;E(n,()=>d).catch(w=>console.error({error:w}));for(let{accountName:w,chain:f,privateKey:A}of e)await R({page:n,privateKey:A,accountName:w,chain:f}),d=!0;await v(n,o.accountName)}o.toggleNetworkMode&&await H({page:n,...o.toggleNetworkMode}),await F(3e3),console.info(wt("greenBright","\u2728 Phantom onboarding completed successfully",{validateStream:!1}))}async function ft(t){let e=t.getByTestId(I.cancelButton);await t.getByTestId("approve-transaction").waitFor({state:"attached"}),await e.click()}async function gt({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 D("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 P{page;constructor(e){super(),this.page=e}async onboard({...e}){await G({page:this.page,...e})}async unlock(){await V(this.page)}async lock(){await lt(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 st({page:this.page,accountName:e,chain:o})}async addAccount({...e}){await R({page:this.page,...e})}async toggleOptionalChains({toggleMode:e,supportedChains:o}){await gt({page:this.page,supportedChains:o,toggleMode:e})}async switchNetwork({...e}){await H({page:this.page,...e})}async connectToApp(e){await ct(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await it(await this.promptPage(this.page.context()))}async rejectTransaction(){await ft(await this.promptPage(this.page.context()))}};import yt from"fs";import Ut from"path";import{test as Ht,chromium as Vt}from"@playwright/test";import{expect as Rt}from"@playwright/test";async function z(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function L(t,e){let o=await t.newPage();return await Rt(async()=>{await o.goto(e),await z(o)}).toPass(),o}async function j(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 Dt from"fs/promises";async function ht(t){await Dt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var $t=35e3;async function K(t,e){try{await Promise.race([t.close(),new Promise((o,a)=>setTimeout(()=>a(new Error("Context close timed out")),$t))])}catch(o){console.warn(`Browser context close did not complete cleanly: ${o.message}`)}try{await ht(e)}catch(o){console.error(`Failed to remove temporary context directory at ${e}. Error:`,o)}}var _,Ka=({slowMo:t=0,profileName:e}={})=>Ht.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 P,u=x(r.name),i=await S(r.name),m=Ut.resolve(u,e??"wallet-data");if(!yt.existsSync(m))throw new Error("\u274C Cache for Phantom wallet data not found. Create it first");yt.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 Vt.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:d}=await o.storageState();h&&await l.addCookies(h),d&&d.length>0&&await j(d,l);let y=await r.indexUrl();_=l.pages().find(f=>f.url().startsWith(y))||await L(l,y);for(let f of l.pages())f.url().includes("about:blank")&&await f.close();await _.bringToFront(),await V(_),await n(l),await K(l,a)},phantomPage:async({context:o},a)=>{await a(_)},phantom:async({context:o},a)=>{let n=new W(_);await a(n)},autoCloseNotification:[async({context:o},a)=>{let n=!1,u=E(_,()=>n);await a(void 0),n=!0,await u.catch(i=>{console.error(`Auto close notification error: ${i.message}`)})},{auto:!0}]});import{test as zt}from"@playwright/test";import xt from"fs";import Kt from"path";import{chromium as Gt}from"@playwright/test";async function Bt({workerInfo:t,profileName:e,slowMo:o}){let a=new P,n=await T(t.workerIndex.toString()),r=x(a.name),u=Kt.resolve(r,e??"wallet-data");if(!xt.existsSync(u))throw new Error(`Cache for ${a.name} does not exist. Create it first!`);xt.cpSync(u,n,{recursive:!0,force:!0});let i=await S(a.name),m=await Gt.launchPersistentContext(n,{headless:!1,args:[`--disable-extensions-except=${i}`],slowMo:process.env.HEADLESS?0:o}),l=await a.indexUrl(),h=await L(m,l);return{context:m,walletPage:h,contextPath:n}}var ln=({slowMo:t,profileName:e}={})=>zt.extend({workerScopeContents:[async({browser:o},a,n)=>{let{context:r,contextPath:u,walletPage:i}=await Bt({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,Ka as phantomFixture,ln as phantomWorkerScopeFixture,ke as workerScopeContext};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { W as WalletProfileFixtureArgs } from '../../types-
|
|
2
|
-
import { W as WorkerScopeFixture } from '../../worker-scope-context-
|
|
3
|
-
export { w as workerScopeContext } from '../../worker-scope-context-
|
|
1
|
+
import { W as WalletProfileFixtureArgs } from '../../types-aoLElQ63.js';
|
|
2
|
+
import { W as WorkerScopeFixture } from '../../worker-scope-context-DSkOcWf-.js';
|
|
3
|
+
export { w as workerScopeContext } from '../../worker-scope-context-DSkOcWf-.js';
|
|
4
4
|
import * as _playwright_test from '@playwright/test';
|
|
5
5
|
import { BrowserContext, Page } from '@playwright/test';
|
|
6
6
|
import z from 'zod';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import G from"fs";import xt from"path";import{chromium as ht}from"@playwright/test";import dt from"path";var K=".wallet-cache",H=".wallet-context";var j="13.33.0",z="0.13.3",C="https://github.com/amaify/chainwright/releases/download/v0.1.0/",wt=`https://github.com/chainapsis/keplr-wallet/releases/download/v${z}/`,ft=`https://github.com/MetaMask/metamask-extension/releases/download/v${j}/`,Nt=`${ft}metamask-chrome-${j}.zip`,Ft=`${C}solflare-wallet-extension-v2.19.1.zip`,Dt=`${C}petra-wallet-extension-v2.4.8.zip`,Lt=`${C}phantom-wallet-extension-v26.10.0.zip`,Rt=`${C}meteor-wallet-extension-v0.7.0.zip`,Ot=`${wt}keplr-extension-manifest-v3-v${z}.zip`;async function h(t){return dt.resolve(process.cwd(),H,t)}import gt from"path";function u(t){return gt.resolve(process.cwd(),K,t)}import q from"fs";import yt from"path";async function S(t){try{let e=u(t),r=yt.resolve(e,"extension-path.txt");if(!q.existsSync(r))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let o=q.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 se({wallet:t,workerInfo:e,profileName:r,slowMo:o}){let a=await h(e.workerIndex.toString()),n=u(t.name),p=xt.resolve(n,r??"wallet-data");if(!G.existsSync(p))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);G.cpSync(p,a,{recursive:!0,force:!0});let l=await S(t.name),c=await ht.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 $ from"zod";var X=$.object({walletName:$.string().min(1,"Wallet name cannot be an empty string"),privateKey:$.string().min(1,"Private key cannot be an empty string")});async function I({page:t,privateKey:e,walletName:r}){let o=X.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 Pt}from"@playwright/test";var E={approveButton:"btn-approve",rejectButton:"btn-reject"};async function J(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
|
-
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
|
|
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 Pt(e).toBeEnabled(),await e.click()}async function v(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 Q(t,e){e&&await v(t,e),await t.getByRole("button",{name:"Connect",exact:!0}).click()}async function Y(t){return await t.getByTestId("icon-section-wallet-picker-copy").click(),await t.evaluate(async()=>await navigator.clipboard.readText())}async function W(t){let e=t.getByRole("button",{name:"settings",exact:!0});await e.waitFor({state:"attached",timeout:3e4}),await e.click()}async function Z(t){await W(t),await t.getByTestId(P.securityAndPrivacyButton).click(),await t.getByTestId("li-settings-lock").getByTestId(P.lockButton).click()}import{styleText as et}from"util";import tt from"fs";import St from"path";async function _(t){let e=u(t),r=St.resolve(e,"password.txt");try{if(!tt.existsSync(r))throw new Error("\u274C password.txt not found. Run setup script first.");return tt.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}){if(e===r){console.warn(`
|
|
4
4
|
|
|
5
|
-
Current account name and new account name are the same: "${e}". Skipping rename.`);return}await t.getByTestId(
|
|
6
|
-
Solflare onboarding started...`,{validateStream:!1}));let n=await
|
|
5
|
+
Current account name and new account name are the same: "${e}". Skipping rename.`);return}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 N(t,e){await W(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 ot({page:t,recoveryPhrase:e,network:r,walletName:o,additionalAccounts:a}){console.info(et("yellowBright",`
|
|
6
|
+
Solflare onboarding started...`,{validateStream:!1}));let n=await _("solflare");await t.getByTestId(y.alreadyHaveAWalletButton).click();let l=e.split(" ");for(let[T,g]of Object.entries(l))await t.getByTestId(`${y.recoveryPhraseInput}-${Number(T)+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(),o&&await M({page:t,currentAccountName:"Main Wallet",newAccountName:o}),r&&await N(t,r),a&&a.length>0)for(let{privateKey:T,walletName:g}of a)await I({page:t,privateKey:T,walletName:g});console.info(et("greenBright","\u2728 Solflare onboarding completed successfully",{validateStream:!1}))}async function rt(t){await t.getByTestId(E.rejectButton).click()}async function F(t){let e=await _("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 At}from"@playwright/test";async function at({context:t,path:e,locator:r}){let o;try{await At.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 Bt(o,r),await o.setViewportSize({width:360,height:592}),o}async function Bt(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 nt from"fs";import kt from"path";async function it(t){let e=u(t),r=kt.resolve(e,"extension-id.txt");try{if(!nt.existsSync(r))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return nt.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 it(this.name)}async promptPage(e){let r=await this.promptUrl();return await at({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 ot({page:this.page,recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a})}async unlock(){await F(this.page)}async lock(){await Z(this.page)}async renameAccount({currentAccountName:e,newAccountName:r}){await M({page:this.page,currentAccountName:e,newAccountName:r})}async switchNetwork(e){await N(this.page,e)}async switchAccount(e){await v(this.page,e)}async getAccountAddress(){return await Y(this.page)}async addAccount({privateKey:e,walletName:r}){await I({page:this.page,privateKey:e,walletName:r})}async connectToApp(e){await Q(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await J(await this.promptPage(this.page.context()))}async rejectTransaction(){await rt(await this.promptPage(this.page.context()))}};import lt from"fs";import It from"path";import{test as Et,chromium as vt}from"@playwright/test";import{expect as bt}from"@playwright/test";async function k(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 bt(async()=>{await r.goto(e),await k(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 Tt from"fs/promises";async function st(t){await Tt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var Ct=35e3;async function D(t,e){try{await Promise.race([t.close(),new Promise((r,o)=>setTimeout(()=>o(new Error("Context close timed out")),Ct))])}catch(r){console.warn(`Browser context close did not complete cleanly: ${r.message}`)}try{await st(e)}catch(r){console.error(`Failed to remove temporary context directory at ${e}. Error:`,r)}}function ct(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 ct(150)}}var b,yr=({slowMo:t=0,profileName:e}={})=>Et.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=It.resolve(p,e??"wallet-data");if(!lt.existsSync(c))throw new Error("\u274C Cache for Solflare wallet data not found. Create it first");await lt.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 vt.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(),O=R.split("#")[0]??"";await m.waitForEvent("page",{predicate:g=>g.url().includes(O),timeout:15e3}),b=m.pages().find(g=>g.url().startsWith(O))||await U(m,R);for(let g of m.pages())g.url().includes("about:blank")&&await g.close();await F(b),await a(m),await D(m,o)},solflarePage:async({context:r},o)=>{await o(b)},solflare:async({context:r},o)=>{let a=new B(b);await o(a)},autoCloseNotification:[async({context:r},o)=>{let a=!1,p=L(b,()=>a);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});import{test as Mt}from"@playwright/test";import pt from"fs";import Wt from"path";import{chromium as _t}from"@playwright/test";async function mt({workerInfo:t,profileName:e,slowMo:r}){let o=new x,a=await h(t.workerIndex.toString()),n=u(o.name),p=Wt.resolve(n,e??"wallet-data");if(!pt.existsSync(p))throw new Error(`Cache for ${o.name} does not exist. Create it first!`);pt.cpSync(p,a,{recursive:!0,force:!0});let l=await S(o.name),c=await _t.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 k(d));for(let w of c.pages())w.url().includes("about:blank")&&await w.close();return{context:c,walletPage:d,contextPath:a}}var Fr=({slowMo:t,profileName:e}={})=>Mt.extend({workerScopeContents:[async({browser:r},o,a)=>{let{context:n,contextPath:p,walletPage:l}=await mt({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 D(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,yr as solflareFixture,Fr as solflareWorkerScopeFixture,se as workerScopeContext};
|
package/package.json
CHANGED