chainwright 0.9.2 → 0.9.4

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.
@@ -16,7 +16,7 @@ declare class SolflareProfile {
16
16
 
17
17
  type OnboardingArgs = {
18
18
  recoveryPhrase: string;
19
- walletName: string;
19
+ walletName?: string;
20
20
  network?: "Mainnet" | "Devnet" | "Testnet";
21
21
  additionalAccounts?: Array<AddAccountArgs>;
22
22
  };
@@ -1,4 +1,6 @@
1
- import q from"fs";import dt from"path";import{chromium as gt}from"@playwright/test";import ut from"path";var K=".wallet-cache",j=".wallet-context";var H="13.33.0",k="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Wt=`https://github.com/MetaMask/metamask-extension/releases/download/v${H}/metamask-chrome-${H}.zip`,Nt=`${k}solflare-wallet-extension-v2.19.1.zip`,Ft=`${k}petra-wallet-extension-v2.4.8.zip`,Mt=`${k}phantom-wallet-extension-v26.10.0.zip`,_t=`${k}meteor-wallet-extension-v0.7.0.zip`,Dt=`${k}keplr-wallet-extension-v0.13.3.zip`;async function h(t){return ut.resolve(process.cwd(),j,t)}import wt from"path";function u(t){return wt.resolve(process.cwd(),K,t)}import z from"fs";import ft from"path";async function S(t){try{let e=u(t),r=ft.resolve(e,"extension-path.txt");if(!z.existsSync(r))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let o=z.readFileSync(r,"utf-8").trim();if(!o)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return o}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function ae({wallet:t,workerInfo:e,profileName:r,slowMo:o}){let a=await h(e.workerIndex.toString()),n=u(t.name),p=dt.resolve(n,r??"wallet-data");if(!q.existsSync(p))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);q.cpSync(p,a,{recursive:!0,force:!0});let l=await S(t.name),c=await gt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:o}),f=await t.indexUrl(),m=c.pages()[0];return m||(m=await c.newPage()),await m.goto(f),{context:c,walletPage:m,contextPath:a}}var P={networkSettings:"li-settings-network",selectNetwork:"select-network",confirmModal:"modal-confirm",confifmButton:"btn-confirm",securityAndPrivacyButton:"nav-item-security-and-privacy",lockButton:"btn-lock"},A={portfolioButton:"nav-item-portfolio",walletSelectorButton:"icon-section-wallet-picker-arrow-right"};import $ from"zod";var G=$.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 b({page:t,privateKey:e,walletName:r}){let o=G.parse({privateKey:e,walletName:r});await t.getByTestId(A.walletSelectorButton).click(),await t.getByTestId("icon-btn-add").click(),await t.getByTestId("li-add-wallet-privateKey-add").click();let l=t.getByTestId("input-name"),c=t.getByTestId("input-private-key");await l.fill(o.walletName),await c.fill(`${o.privateKey}`),await t.getByTestId("btn-import").click(),await t.locator("span:has-text('My wallets')").waitFor({state:"attached"}),await t.getByRole("dialog").getByTestId("icon-btn-close").click()}import{expect as yt}from"@playwright/test";var v={approveButton:"btn-approve",rejectButton:"btn-reject"};async function X(t){let e=t.getByTestId(v.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(`
1
+ import q from"fs";import dt from"path";import{chromium as gt}from"@playwright/test";import ut from"path";var K=".wallet-cache",j=".wallet-context";var H="13.33.0",k="https://github.com/amaify/chainwright/releases/download/v0.1.0/",Wt=`https://github.com/MetaMask/metamask-extension/releases/download/v${H}/metamask-chrome-${H}.zip`,Ft=`${k}solflare-wallet-extension-v2.19.1.zip`,Mt=`${k}petra-wallet-extension-v2.4.8.zip`,Nt=`${k}phantom-wallet-extension-v26.10.0.zip`,_t=`${k}meteor-wallet-extension-v0.7.0.zip`,Dt=`${k}keplr-wallet-extension-v0.13.3.zip`;async function h(t){return ut.resolve(process.cwd(),j,t)}import wt from"path";function u(t){return wt.resolve(process.cwd(),K,t)}import z from"fs";import ft from"path";async function S(t){try{let e=u(t),r=ft.resolve(e,"extension-path.txt");if(!z.existsSync(r))throw new Error("\u274C extension-path.txt not found. Run setup script first.");let o=z.readFileSync(r,"utf-8").trim();if(!o)throw new Error("\u274C extension-path.txt is empty. Run setup script first.");return o}catch(e){throw new Error(`\u274C Failed to get ${t} extension path: ${e.message}`)}}async function ae({wallet:t,workerInfo:e,profileName:r,slowMo:o}){let a=await h(e.workerIndex.toString()),n=u(t.name),p=dt.resolve(n,r??"wallet-data");if(!q.existsSync(p))throw new Error(`Cache for ${t.name} does not exist. Create it first!`);q.cpSync(p,a,{recursive:!0,force:!0});let l=await S(t.name),c=await gt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:o}),f=await t.indexUrl(),m=c.pages()[0];return m||(m=await c.newPage()),await m.goto(f),{context:c,walletPage:m,contextPath:a}}var P={networkSettings:"li-settings-network",selectNetwork:"select-network",confirmModal:"modal-confirm",confifmButton:"btn-confirm",securityAndPrivacyButton:"nav-item-security-and-privacy",lockButton:"btn-lock"},B={portfolioButton:"nav-item-portfolio",walletSelectorButton:"icon-section-wallet-picker-arrow-right"};import $ from"zod";var G=$.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 b({page:t,privateKey:e,walletName:r}){let o=G.parse({privateKey:e,walletName:r});await t.getByTestId(B.walletSelectorButton).click(),await t.getByTestId("icon-btn-add").click(),await t.getByTestId("li-add-wallet-privateKey-add").click();let l=t.getByTestId("input-name"),c=t.getByTestId("input-private-key");await l.fill(o.walletName),await c.fill(`${o.privateKey}`),await t.getByTestId("btn-import").click(),await t.locator("span:has-text('My wallets')").waitFor({state:"attached"}),await t.getByRole("dialog").getByTestId("icon-btn-close").click()}import{expect as yt}from"@playwright/test";var v={approveButton:"btn-approve",rejectButton:"btn-reject"};async function X(t){let e=t.getByTestId(v.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 yt(e).toBeEnabled(),await e.click()}async function E(t,e){await t.getByTestId("icon-section-wallet-picker-arrow-right").click();let o=t.getByTestId("list-item-m-title").filter({hasText:e}).locator("xpath=../..");if(!await o.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is onboarded or verify the account name.`);await o.click()}async function J(t,e){e&&await E(t,e),await t.getByRole("button",{name:"Connect",exact:!0}).click()}async function Q(t){return await t.getByTestId("icon-section-wallet-picker-copy").click(),await t.evaluate(async()=>await navigator.clipboard.readText())}async function W(t){let e=t.getByRole("button",{name:"settings",exact:!0});await e.waitFor({state:"attached",timeout:3e4}),await e.click()}async function Y(t){await W(t),await t.getByTestId(P.securityAndPrivacyButton).click(),await t.getByTestId("li-settings-lock").getByTestId(P.lockButton).click()}import{styleText as tt}from"util";import Z from"fs";import xt from"path";async function N(t){let e=u(t),r=xt.resolve(e,"password.txt");try{if(!Z.existsSync(r))throw new Error("\u274C password.txt not found. Run setup script first.");return Z.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} password from cache: ${o.message}`)}}var y={alreadyHaveAWalletButton:"btn-already-have-wallet",recoveryPhraseInput:"input-recovery-phrase",continueButton:"btn-continue",passwordInput:"input-new-password",repeatPasswordInput:"input-repeat-password",quickSetupButton:"btn-quick-setup",IAgreeButton:"btn-explore"};async function F({page:t,currentAccountName:e,newAccountName:r}){await t.getByTestId(A.walletSelectorButton).click();let a=t.locator(`button[data-testid^='li-wallets']:has-text('${e}')`);if(!await a.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is available.`);await a.hover({timeout:2e4}),await a.getByTestId("icon-btn-three-dots").click({timeout:2e4});let l=t.getByTestId("li-manage-wallet-rename-wallet");await l.click();let c=t.getByTestId("input-name");await c.clear(),await c.fill(r),await t.getByTestId("btn-save").click(),await l.waitFor({state:"attached",timeout:15e3}),await t.getByTestId("icon-btn-close").click()}async function M(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 et({page:t,recoveryPhrase:e,network:r,walletName:o,additionalAccounts:a}){console.info(tt("yellowBright",`
4
- Solflare onboarding started...`,{validateStream:!1}));let n=await N("solflare");await t.getByTestId(y.alreadyHaveAWalletButton).click();let l=e.split(" ");for(let[I,g]of Object.entries(l))await t.getByTestId(`${y.recoveryPhraseInput}-${Number(I)+1}`).fill(g);let c=t.getByTestId(y.continueButton);await c.click();let f=t.getByTestId(y.passwordInput),m=t.getByTestId(y.repeatPasswordInput);if(await f.fill(n),await m.fill(n),await c.click(),await t.locator("div",{hasText:"Detecting your existing accounts. This process can take up to a minute."}).waitFor({state:"detached"}),await t.getByTestId(y.quickSetupButton).click(),await t.getByTestId(y.IAgreeButton).click(),await F({page:t,currentAccountName:"Main Wallet",newAccountName:o}),r&&await M(t,r),a&&a.length>0)for(let{privateKey:I,walletName:g}of a)await b({page:t,privateKey:I,walletName:g});console.info(tt("greenBright","\u2728 Solflare onboarding completed successfully",{validateStream:!1}))}async function ot(t){await t.getByTestId(v.rejectButton).click()}async function _(t){let e=await N("solflare");await t.getByTestId("input-password").fill(e),await t.getByTestId("btn-unlock").click(),await t.getByTestId("nav-main").waitFor({state:"attached",timeout:3e4})}import{expect as ht}from"@playwright/test";async function rt({context:t,path:e,locator:r}){let o;try{await ht.poll(async()=>(o=t.pages().filter(a=>a.url().startsWith("chrome-extension://")).find(a=>a.url().match(e)),!!o),{timeout:3e4}).toBe(!0)}catch{let a=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).map(n=>n.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(a)}`)}if(!o)throw new Error(`Popup page with path ${e} not found in context.`);return await Pt(o,r),await o.setViewportSize({width:360,height:592}),o}async function Pt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import at from"fs";import St from"path";async function nt(t){let e=u(t),r=St.resolve(e,"extension-id.txt");try{if(!at.existsSync(r))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${o.message}`)}}var x=class{name="solflare";onboardingPath="wallet.html#/onboard";async indexUrl(){return`chrome-extension://${await this.extensionId()}/wallet.html#/portfolio`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/confirm_popup.html`}async extensionId(){return await nt(this.name)}async promptPage(e){let r=await this.promptUrl();return await rt({context:e,path:r,locator:"div[data-testid='page-dapp-connect'], div[data-testid='page-tx-sign']"})}};var B=class extends x{page;constructor(e){super(),this.page=e}async onboard({recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a}){await et({page:this.page,recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a})}async unlock(){await _(this.page)}async lock(){await Y(this.page)}async renameAccount({currentAccountName:e,newAccountName:r}){await F({page:this.page,currentAccountName:e,newAccountName:r})}async switchNetwork(e){await M(this.page,e)}async switchAccount(e){await E(this.page,e)}async getAccountAddress(){return await Q(this.page)}async addAccount({privateKey:e,walletName:r}){await b({page:this.page,privateKey:e,walletName:r})}async connectToApp(e){await J(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await X(await this.promptPage(this.page.context()))}async rejectTransaction(){await ot(await this.promptPage(this.page.context()))}};import ct from"fs";import Ct from"path";import{test as Tt,chromium as It}from"@playwright/test";import{expect as At}from"@playwright/test";async function C(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function U(t,e){let r=await t.newPage();return await At(async()=>{await r.goto(e),await C(r)}).toPass(),r}async function V(t,e){let r=await e.newPage();for(let{origin:o,localStorage:a}of t){let n=r.mainFrame();await n.goto(o),await n.evaluate(p=>{p.forEach(({name:l,value:c})=>{window.localStorage.setItem(l,c)})},a)}await r.close()}import Bt from"fs/promises";async function it(t){await Bt.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var kt=35e3;async function D(t,e){try{await Promise.race([t.close(),new Promise((r,o)=>setTimeout(()=>o(new Error("Context close timed out")),kt))])}catch(r){console.warn(`Browser context close did not complete cleanly: ${r.message}`)}try{await it(e)}catch(r){console.error(`Failed to remove temporary context directory at ${e}. Error:`,r)}}function st(t){return new Promise(e=>setTimeout(e,t))}async function O(t,e){let o=!1;for(;!e();){let a=e();if(a||o||t.isClosed())break;try{let n=t.locator("div[role='dialog']").locator("button[data-testid='icon-btn-whats-new-modal-close']");await n.isVisible().catch(()=>!1)&&(await n.click(),o=!0)}catch(n){console.error("[autoCloseSolflareNotification]: ",n)}if(a||o||t.isClosed())break;await st(150)}}var T,fr=({slowMo:t=0,profileName:e}={})=>Tt.extend({contextPath:async({browserName:r},o,a)=>{let n=await h(`${r}-${a.testId}`);await o(n)},context:async({context:r,contextPath:o},a)=>{let n=new x,p=u(n.name),l=await S(n.name),c=Ct.resolve(p,e??"wallet-data");if(!ct.existsSync(c))throw new Error("\u274C Cache for Solflare wallet data not found. Create it first");await ct.promises.cp(c,o,{recursive:!0,force:!0});let f=[`--disable-extensions-except=${l}`,`--load-extension=${l}`];process.env.HEADLESS&&(f.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let m=await It.launchPersistentContext(o,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:t});await m.grantPermissions(["clipboard-read"]);let{cookies:d,origins:w}=await r.storageState();d&&await m.addCookies(d),w&&w.length>0&&V(w,m);let L=await n.indexUrl(),R=L.split("#")[0]??"";await m.waitForEvent("page",{predicate:g=>g.url().includes(R),timeout:15e3}),T=m.pages().find(g=>g.url().startsWith(R))||await U(m,L);for(let g of m.pages())g.url().includes("about:blank")&&await g.close();await _(T),await a(m),await D(m,o)},solflarePage:async({context:r},o)=>{await o(T)},solflare:async({context:r},o)=>{let a=new B(T);await o(a)},autoCloseNotification:[async({context:r},o)=>{let a=!1,p=O(T,()=>a);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});import{test as Et}from"@playwright/test";import lt from"fs";import bt from"path";import{chromium as vt}from"@playwright/test";async function pt({workerInfo:t,profileName:e,slowMo:r}){let o=new x,a=await h(t.workerIndex.toString()),n=u(o.name),p=bt.resolve(n,e??"wallet-data");if(!lt.existsSync(p))throw new Error(`Cache for ${o.name} does not exist. Create it first!`);lt.cpSync(p,a,{recursive:!0,force:!0});let l=await S(o.name),c=await vt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:r}),f=await o.indexUrl(),m=f.split("#")[0]??"";await c.waitForEvent("page",{predicate:w=>w.url().includes(m),timeout:15e3});let d=c.pages().find(w=>w.url().startsWith(m));d||(d=await c.newPage(),await d.goto(f),await C(d));for(let w of c.pages())w.url().includes("about:blank")&&await w.close();return{context:c,walletPage:d,contextPath:a}}var Nr=({slowMo:t,profileName:e}={})=>Et.extend({workerScopeContents:[async({browser:r},o,a)=>{let{context:n,contextPath:p,walletPage:l}=await pt({workerInfo:a,profileName:e,slowMo:t});await n.grantPermissions(["clipboard-read"]);let c=new B(l);await c.unlock(),await o({wallet:c,walletPage:l,context:n}),await D(n,p)},{scope:"worker"}],autoCloseNotification:[async({workerScopeContents:r},o)=>{let a=!1,n=()=>a,p=O(r.walletPage,n);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});export{B as Solflare,fr as solflareFixture,Nr as solflareWorkerScopeFixture,ae as workerScopeContext};
3
+ A 'Network mismatch' error was detected in the transaction confirmation popup. Closing the popup and aborting the transaction confirmation process.`),await t.getByRole("button",{name:"Close",exact:!0}).click();return}let n=t.locator("div[data-id='control-label']");await n.isVisible().catch(()=>!1)&&await n.click(),await yt(e).toBeEnabled(),await e.click()}async function E(t,e){await t.getByTestId("icon-section-wallet-picker-arrow-right").click();let o=t.getByTestId("list-item-m-title").filter({hasText:e}).locator("xpath=../..");if(!await o.isVisible().catch(()=>!1))throw new Error(`Account "${e}" not found. Make sure the account is onboarded or verify the account name.`);await o.click()}async function J(t,e){e&&await E(t,e),await t.getByRole("button",{name:"Connect",exact:!0}).click()}async function Q(t){return await t.getByTestId("icon-section-wallet-picker-copy").click(),await t.evaluate(async()=>await navigator.clipboard.readText())}async function W(t){let e=t.getByRole("button",{name:"settings",exact:!0});await e.waitFor({state:"attached",timeout:3e4}),await e.click()}async function Y(t){await W(t),await t.getByTestId(P.securityAndPrivacyButton).click(),await t.getByTestId("li-settings-lock").getByTestId(P.lockButton).click()}import{styleText as tt}from"util";import Z from"fs";import xt from"path";async function F(t){let e=u(t),r=xt.resolve(e,"password.txt");try{if(!Z.existsSync(r))throw new Error("\u274C password.txt not found. Run setup script first.");return Z.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} password from cache: ${o.message}`)}}var y={alreadyHaveAWalletButton:"btn-already-have-wallet",recoveryPhraseInput:"input-recovery-phrase",continueButton:"btn-continue",passwordInput:"input-new-password",repeatPasswordInput:"input-repeat-password",quickSetupButton:"btn-quick-setup",IAgreeButton:"btn-explore"};async function M({page:t,currentAccountName:e,newAccountName:r}){if(e===r){console.warn(`
4
+
5
+ Current account name and new account name are the same: "${e}". Skipping rename.`);return}await t.getByTestId(B.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(B.portfolioButton).click()}async function et({page:t,recoveryPhrase:e,network:r,walletName:o,additionalAccounts:a}){console.info(tt("yellowBright",`
6
+ Solflare onboarding started...`,{validateStream:!1}));let n=await F("solflare");await t.getByTestId(y.alreadyHaveAWalletButton).click();let l=e.split(" ");for(let[I,g]of Object.entries(l))await t.getByTestId(`${y.recoveryPhraseInput}-${Number(I)+1}`).fill(g);let c=t.getByTestId(y.continueButton);await c.click();let f=t.getByTestId(y.passwordInput),m=t.getByTestId(y.repeatPasswordInput);if(await f.fill(n),await m.fill(n),await c.click(),await t.locator("div",{hasText:"Detecting your existing accounts. This process can take up to a minute."}).waitFor({state:"detached"}),await t.getByTestId(y.quickSetupButton).click(),await t.getByTestId(y.IAgreeButton).click(),o&&await M({page:t,currentAccountName:"Main Wallet",newAccountName:o}),r&&await N(t,r),a&&a.length>0)for(let{privateKey:I,walletName:g}of a)await b({page:t,privateKey:I,walletName:g});console.info(tt("greenBright","\u2728 Solflare onboarding completed successfully",{validateStream:!1}))}async function ot(t){await t.getByTestId(v.rejectButton).click()}async function _(t){let e=await F("solflare");await t.getByTestId("input-password").fill(e),await t.getByTestId("btn-unlock").click(),await t.getByTestId("nav-main").waitFor({state:"attached",timeout:3e4})}import{expect as ht}from"@playwright/test";async function rt({context:t,path:e,locator:r}){let o;try{await ht.poll(async()=>(o=t.pages().filter(a=>a.url().startsWith("chrome-extension://")).find(a=>a.url().match(e)),!!o),{timeout:3e4}).toBe(!0)}catch{let a=t.pages().filter(n=>n.url().startsWith("chrome-extension://")).map(n=>n.url());throw new Error(`Popup page with path "${e}" not found in context after 30s. Pages in context: ${JSON.stringify(a)}`)}if(!o)throw new Error(`Popup page with path ${e} not found in context.`);return await Pt(o,r),await o.setViewportSize({width:360,height:592}),o}async function Pt(t,e){await t.waitForLoadState("load",{timeout:4e4}),await t.waitForLoadState("domcontentloaded",{timeout:4e4}),await t.locator(e).first().waitFor({state:"attached",timeout:4e4})}import at from"fs";import St from"path";async function nt(t){let e=u(t),r=St.resolve(e,"extension-id.txt");try{if(!at.existsSync(r))throw new Error("\u274C extension-id.txt not found. Run setup script first.");return at.readFileSync(r,"utf-8")}catch(o){throw new Error(`\u274C Failed to get ${t} extension ID from cache: ${o.message}`)}}var x=class{name="solflare";onboardingPath="wallet.html#/onboard";async indexUrl(){return`chrome-extension://${await this.extensionId()}/wallet.html#/portfolio`}async promptUrl(){return`chrome-extension://${await this.extensionId()}/confirm_popup.html`}async extensionId(){return await nt(this.name)}async promptPage(e){let r=await this.promptUrl();return await rt({context:e,path:r,locator:"div[data-testid='page-dapp-connect'], div[data-testid='page-tx-sign']"})}};var A=class extends x{page;constructor(e){super(),this.page=e}async onboard({recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a}){await et({page:this.page,recoveryPhrase:e,network:r,additionalAccounts:o,walletName:a})}async unlock(){await _(this.page)}async lock(){await Y(this.page)}async renameAccount({currentAccountName:e,newAccountName:r}){await M({page:this.page,currentAccountName:e,newAccountName:r})}async switchNetwork(e){await N(this.page,e)}async switchAccount(e){await E(this.page,e)}async getAccountAddress(){return await Q(this.page)}async addAccount({privateKey:e,walletName:r}){await b({page:this.page,privateKey:e,walletName:r})}async connectToApp(e){await J(await this.promptPage(this.page.context()),e)}async confirmTransaction(){await X(await this.promptPage(this.page.context()))}async rejectTransaction(){await ot(await this.promptPage(this.page.context()))}};import ct from"fs";import Ct from"path";import{test as Tt,chromium as It}from"@playwright/test";import{expect as Bt}from"@playwright/test";async function C(t){await t.waitForLoadState("load",{timeout:15e3}),await t.waitForLoadState("domcontentloaded",{timeout:15e3})}async function U(t,e){let r=await t.newPage();return await Bt(async()=>{await r.goto(e),await C(r)}).toPass(),r}async function V(t,e){let r=await e.newPage();for(let{origin:o,localStorage:a}of t){let n=r.mainFrame();await n.goto(o),await n.evaluate(p=>{p.forEach(({name:l,value:c})=>{window.localStorage.setItem(l,c)})},a)}await r.close()}import At from"fs/promises";async function it(t){await At.rm(t,{maxRetries:50,retryDelay:500,recursive:!0,force:!0})}var kt=35e3;async function D(t,e){try{await Promise.race([t.close(),new Promise((r,o)=>setTimeout(()=>o(new Error("Context close timed out")),kt))])}catch(r){console.warn(`Browser context close did not complete cleanly: ${r.message}`)}try{await it(e)}catch(r){console.error(`Failed to remove temporary context directory at ${e}. Error:`,r)}}function st(t){return new Promise(e=>setTimeout(e,t))}async function O(t,e){let o=!1;for(;!e();){let a=e();if(a||o||t.isClosed())break;try{let n=t.locator("div[role='dialog']").locator("button[data-testid='icon-btn-whats-new-modal-close']");await n.isVisible().catch(()=>!1)&&(await n.click(),o=!0)}catch(n){console.error("[autoCloseSolflareNotification]: ",n)}if(a||o||t.isClosed())break;await st(150)}}var T,fr=({slowMo:t=0,profileName:e}={})=>Tt.extend({contextPath:async({browserName:r},o,a)=>{let n=await h(`${r}-${a.testId}`);await o(n)},context:async({context:r,contextPath:o},a)=>{let n=new x,p=u(n.name),l=await S(n.name),c=Ct.resolve(p,e??"wallet-data");if(!ct.existsSync(c))throw new Error("\u274C Cache for Solflare wallet data not found. Create it first");await ct.promises.cp(c,o,{recursive:!0,force:!0});let f=[`--disable-extensions-except=${l}`,`--load-extension=${l}`];process.env.HEADLESS&&(f.push("--headless=new"),t>0&&console.warn("\u26A0\uFE0F Slow motion makes no sense in headless mode. It will be ignored!"));let m=await It.launchPersistentContext(o,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:t});await m.grantPermissions(["clipboard-read"]);let{cookies:d,origins:w}=await r.storageState();d&&await m.addCookies(d),w&&w.length>0&&V(w,m);let L=await n.indexUrl(),R=L.split("#")[0]??"";await m.waitForEvent("page",{predicate:g=>g.url().includes(R),timeout:15e3}),T=m.pages().find(g=>g.url().startsWith(R))||await U(m,L);for(let g of m.pages())g.url().includes("about:blank")&&await g.close();await _(T),await a(m),await D(m,o)},solflarePage:async({context:r},o)=>{await o(T)},solflare:async({context:r},o)=>{let a=new A(T);await o(a)},autoCloseNotification:[async({context:r},o)=>{let a=!1,p=O(T,()=>a);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});import{test as Et}from"@playwright/test";import lt from"fs";import bt from"path";import{chromium as vt}from"@playwright/test";async function pt({workerInfo:t,profileName:e,slowMo:r}){let o=new x,a=await h(t.workerIndex.toString()),n=u(o.name),p=bt.resolve(n,e??"wallet-data");if(!lt.existsSync(p))throw new Error(`Cache for ${o.name} does not exist. Create it first!`);lt.cpSync(p,a,{recursive:!0,force:!0});let l=await S(o.name),c=await vt.launchPersistentContext(a,{headless:!1,args:[`--disable-extensions-except=${l}`],slowMo:process.env.HEADLESS?0:r}),f=await o.indexUrl(),m=f.split("#")[0]??"";await c.waitForEvent("page",{predicate:w=>w.url().includes(m),timeout:15e3});let d=c.pages().find(w=>w.url().startsWith(m));d||(d=await c.newPage(),await d.goto(f),await C(d));for(let w of c.pages())w.url().includes("about:blank")&&await w.close();return{context:c,walletPage:d,contextPath:a}}var Fr=({slowMo:t,profileName:e}={})=>Et.extend({workerScopeContents:[async({browser:r},o,a)=>{let{context:n,contextPath:p,walletPage:l}=await pt({workerInfo:a,profileName:e,slowMo:t});await n.grantPermissions(["clipboard-read"]);let c=new A(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=O(r.walletPage,n);await o(void 0),a=!0,await p.catch(l=>{console.error(`Auto close notification error: ${l.message}`)})},{auto:!0}]});export{A as Solflare,fr as solflareFixture,Fr as solflareWorkerScopeFixture,ae as workerScopeContext};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chainwright",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Playwright Web3 wallet testing framework for end-to-end dApp automation with MetaMask, Phantom, Solflare, Petra, Meteor, and Keplr",
5
5
  "type": "module",
6
6
  "license": "MIT",