diff --git a/authservice/login-with-passwordless/DashboardPage.ts b/authservice/login-with-passwordless/DashboardPage.ts index 42f626a..9dc7d39 100644 --- a/authservice/login-with-passwordless/DashboardPage.ts +++ b/authservice/login-with-passwordless/DashboardPage.ts @@ -27,4 +27,58 @@ export class DashboardPage { const content = await this.page.locator(".card-container pre").textContent(); return JSON.parse(content); } + + async getUserInfoObjectByText() { + await this.page.locator("text=Get User Info").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return JSON.parse(content); + } + + async getAccountValueByText() { + await this.page.locator("text=Get Accounts").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return content.trim(); + } + + async getBalanceValueByText() { + await this.page.locator("text=Get Balance").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return content.trim(); + } + + async getSignTransactionValueByText() { + await this.page.locator("text=Sign Transaction").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return content.trim(); + } + + async getSignETHMessageValueByText() { + await this.page.locator("text=Sign ETH Message").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return content.trim(); + } + + async getGetConnectedChainIDValueByText() { + await this.page.locator("text=Get Connected Chain ID").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return content.trim(); + } + + async getSignTypedDatav4ValueByText() { + await this.page.locator("text=Sign Typed Data v4").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return JSON.parse(content); + } + + async getSignPersonalMessageValueByText() { + await this.page.locator("text=Sign Personal Message").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return JSON.parse(content); + } + + async getGetIdTokenValueByText() { + await this.page.locator("text=Get id token").click(); + const content = await this.page.locator(".card-container pre").textContent(); + return JSON.parse(content); + } } diff --git a/authservice/login-with-passwordless/LoginPage.ts b/authservice/login-with-passwordless/LoginPage.ts index 025d1b2..b4f1196 100644 --- a/authservice/login-with-passwordless/LoginPage.ts +++ b/authservice/login-with-passwordless/LoginPage.ts @@ -1,15 +1,17 @@ // playwright-dev-page.ts import { Page } from "@playwright/test"; -async function selectSingleChoiceDropdown(page: Page, dataTestId: string, option: string) { +export async function selectSingleChoiceDropdown(page: Page, dataTestId: string, option: string, clickDropdown = false) { await page.locator(`[data-testid="${dataTestId}"]`).waitFor({ state: "visible" }); await page.click(`[data-testid="${dataTestId}"] button`); await page.click(`//*[@data-testid="${dataTestId}"]//span[text()="${option}"]`); await page.locator(`//*[@data-testid="${dataTestId}"]//button[text()="${option}"]`).waitFor({ state: "visible" }); + + if (clickDropdown) await page.click(`[data-testid="${dataTestId}"] button`); } -async function selectMultipleChoicesDropdown(page: Page, dataTestId: string, options: string[]) { +export async function selectMultipleChoicesDropdown(page: Page, dataTestId: string, options: string[]) { await page.locator(`[data-testid="${dataTestId}"]`).waitFor({ state: "visible" }); await page.click(`[data-testid="${dataTestId}"] button`); diff --git a/sdkweb3auth/SdkLoginPage.ts b/sdkweb3auth/SdkLoginPage.ts new file mode 100644 index 0000000..016c317 --- /dev/null +++ b/sdkweb3auth/SdkLoginPage.ts @@ -0,0 +1,165 @@ +import { FrameLocator, Page } from "@playwright/test"; + +import { selectMultipleChoicesDropdown, selectSingleChoiceDropdown } from "../authservice/login-with-passwordless/LoginPage"; +import { delay } from "../authservice/utils"; + +export async function checkVisible(page: Page, locator: string, timeout = 5000) { + try { + await page.waitForSelector(locator, { state: "visible", timeout }); + return true; + } catch (error) { + return false; + } +} + +export async function switchOnOff(page: Page, nameSwitch: string, turnOn = true) { + const isOn = await page.locator(`//div[div/span[text()="${nameSwitch}"]]/label/input`).isChecked(); + + if (isOn !== turnOn) await page.click(`//div[div/span[text()="${nameSwitch}"]]/label`); +} + +export async function checkVisibleIframe(frame: FrameLocator, locator: string, timeout = 5000) { + try { + await frame.locator(locator).waitFor({ state: "visible", timeout }); + return true; + } catch (error) { + return false; + } +} + +export class SdkLoginPage { + readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + async gotoSdkLoginPage(link: string) { + await this.page.goto(link); + } + + async clickConnectButton() { + await delay(1000); + await this.page.click(`[data-testid="loginButton"]`); + } + + async clickTab(tabName: string) { + await this.page.click(`//li[contains(@class,'tab-container')]/div[text()='${tabName}']`); + await checkVisible(this.page, `//li[@aria-selected="true" and contains(@class,'tab-container')]/div[text()='${tabName}']`); + } + + async selectNetwork(network: string) { + await selectSingleChoiceDropdown(this.page, "selectNetwork", network); + } + + async selectChainNamespace(chainNamespace: string) { + await selectSingleChoiceDropdown(this.page, "selectChainNamespace", chainNamespace); + } + + async selectChain(chain: string) { + await selectSingleChoiceDropdown(this.page, "selectChain", chain); + } + + async selectLoginProvider(provider: string) { + await selectSingleChoiceDropdown(this.page, "selectLoginProviders", provider, true); + } + + async selectSmartAccountType(type: string) { + await selectSingleChoiceDropdown(this.page, "smartAccountType", type, true); + } + + async selectAdapters(adapterList: string[]) { + await selectMultipleChoicesDropdown(this.page, "selectAdapters", adapterList); + } + + async selectTab(tabName: string) { + await this.page.click(`//li[@role="tab"]/div[text()="${tabName}"]`); + } + + async turnOnOffMainOption(turnOn = true) { + await switchOnOff(this.page, "Main Option", turnOn); + } + + async turnOnOffonModal(turnOn = true) { + await switchOnOff(this.page, "on Modal?", turnOn); + } + + async turnOnOffAccountAbstractionProvider(turnOn = true) { + await switchOnOff(this.page, "Account Abstraction Provider", turnOn); + } + + async turnOnOffUseAccountAbstractionProviderWithExternalWallet(turnOn = true) { + await switchOnOff(this.page, "Use Account Abstraction Provider with external wallet", turnOn); + } + + async inputEmailW3Modal(email: string) { + await this.page.fill(`#w3a-modal input[name="passwordless-input"]`, email); + } + + async clickContinueBtnW3Modal() { + await this.page.click(`//div[@id="w3a-modal"]//button[text()="Continue"]`); + } + + async clickConnectWalletsBtnW3Modal() { + await this.page.click(`//div[@id="w3a-modal"]//button[text()="Continue with a wallet"]`); + } + + async clickClosebtnW3Modal() { + await this.page.click(`#w3a-modal button.w3ajs-close-btn`); + } + + async clickWalletW3Modal(walletName: string) { + await this.page.click(`button[title="${walletName}"]`); + } + + async clickBackBtnW3Modal() { + await this.page.click(`#w3a-modal button.w3ajs-external-back`); + } + + async isQRCodeW3ModalDisplay(walletName: string) { + return checkVisible(this.page, `text="${walletName}"`) && checkVisible(this.page, `.w3ajs-wallet-connect-qr`); + } + + async isWalletInstallationW3ModalDisplay(walletName: string) { + const isTitleDisplay = await checkVisible(this.page, `text="Get ${walletName}"`); + const isChromeXtensionDisplay = await checkVisible(this.page, 'text="Install Chrome extension"'); + const isAndroidDisplay = await checkVisible(this.page, 'text="Install Android app"'); + const isiOSDisplay = await checkVisible(this.page, 'text="Install iOS app"'); + return isTitleDisplay && isChromeXtensionDisplay && isAndroidDisplay && isiOSDisplay; + } + + async isWalletInfoInW3ModalDisplay(walletName: string) { + const isQRDisplay = await checkVisible(this.page, `text="${walletName}"`); + + if (isQRDisplay) return checkVisible(this.page, `.w3ajs-wallet-connect-qr`); + + const isTitleDisplay = await checkVisible(this.page, `text="Get ${walletName}"`); + const isChromeXtensionDisplay = await checkVisible(this.page, 'text="Install Chrome extension"'); + const isAndroidDisplay = await checkVisible(this.page, 'text="Install Android app"'); + const isiOSDisplay = await checkVisible(this.page, 'text="Install iOS app"'); + return isTitleDisplay && isChromeXtensionDisplay && isAndroidDisplay && isiOSDisplay; + } + + async isTorusEmailLoginW3ModalDisplay() { + const iframe = this.page.frameLocator("#torusIframe"); + return checkVisibleIframe(iframe, "button.gmt-login-email"); + } + + async isLoginW3ModalDisplay() { + const iframe = this.page.frameLocator("#torusIframe"); + return checkVisibleIframe(iframe, `.login-dialog-container`); + } + + async isAdapterListW3ModalDisplay() { + return checkVisible(this.page, `div#w3a-modal .w3a-modal__content_external_wallet`); + } + + async closeLoginW3Modal() { + const iframe = this.page.frameLocator("#torusIframe"); + await iframe.locator(`.login-dialog-container .close-btn`).click(); + } + + async logout() { + await this.page.click('text="Logout"'); + } +} diff --git a/sdkweb3auth/sdk.test.ts b/sdkweb3auth/sdk.test.ts new file mode 100644 index 0000000..70f0e0c --- /dev/null +++ b/sdkweb3auth/sdk.test.ts @@ -0,0 +1,126 @@ +import { expect, test } from "@playwright/test"; + +import { DashboardPage } from "../authservice/login-with-passwordless/DashboardPage"; +import { delay, generateEmailWithTag, verifyEmailPasswordlessWithVerificationCode } from "../authservice/utils"; +import { SdkLoginPage } from "./SdkLoginPage"; + +test.describe("SDK demo web3auth scenarios", () => { + test.setTimeout(120000); + + test("Can show wallet list @walletList", async ({ page, browser }) => { + const testEmail = generateEmailWithTag(); + const loginPage = new SdkLoginPage(page); + + await loginPage.gotoSdkLoginPage("https://demo-sdk.web3auth.io/"); + await loginPage.clickTab("General"); + await loginPage.selectNetwork("sapphire_mainnet"); + + // ETH + await loginPage.selectChainNamespace("eip155"); + await loginPage.selectChain("0x1 Ethereum"); + await loginPage.selectAdapters(["coinbase-adapter", "torus-evm-adapter", "wallet-connect-v2-adapter", "injected-adapters"]); + await loginPage.clickConnectButton(); + + await loginPage.clickConnectWalletsBtnW3Modal(); + + await loginPage.clickWalletW3Modal("metamask"); + expect(await loginPage.isWalletInfoInW3ModalDisplay("MetaMask")).toBeTruthy(); + await loginPage.clickBackBtnW3Modal(); + + await loginPage.clickWalletW3Modal("phantom"); + expect(await loginPage.isWalletInstallationW3ModalDisplay("Phantom")).toBeTruthy(); + await loginPage.clickBackBtnW3Modal(); + + await loginPage.clickWalletW3Modal("torus-evm"); + expect(await loginPage.isTorusEmailLoginW3ModalDisplay()).toBeTruthy(); + await loginPage.closeLoginW3Modal(); + await loginPage.clickClosebtnW3Modal(); + + // LOGIN BY EMAIL PASSWORDLESS + await loginPage.clickConnectButton(); + await loginPage.inputEmailW3Modal(testEmail); + await loginPage.clickContinueBtnW3Modal(); + + const currentTimestamp = Math.floor(Date.now() / 1000); + const tag = testEmail.split("@")[0].split(".")[1]; + + await verifyEmailPasswordlessWithVerificationCode(page, browser, { + email: testEmail, + tag, + timestamp: currentTimestamp, + redirectMode: false, + previousCode: "", + }); + + await delay(2000); + + const dashboardPage = new DashboardPage(page); + expect(await dashboardPage.getUserInfoObjectByText()).not.toBeUndefined(); + expect(await dashboardPage.getAccountValueByText()).not.toBe(""); + expect(await dashboardPage.getBalanceValueByText()).not.toBe(""); + expect(await dashboardPage.getSignTransactionValueByText()).not.toBe(""); + expect(await dashboardPage.getSignETHMessageValueByText()).not.toBe(""); + expect(await dashboardPage.getGetConnectedChainIDValueByText()).not.toBe(""); + expect((await dashboardPage.getSignTypedDatav4ValueByText()).signedMessage as string).not.toBe(""); + expect((await dashboardPage.getSignPersonalMessageValueByText()).signedMessage as string).not.toBe(""); + expect((await dashboardPage.getGetIdTokenValueByText()).idToken as string).not.toBe(""); + await loginPage.logout(); + + // SOLANA + await loginPage.selectChainNamespace("solana"); + await loginPage.selectChain("0x1 Solana Mainnet"); + await loginPage.selectAdapters(["torus-solana-adapter", "wallet-connect-v2-adapter", "injected-adapters"]); + await loginPage.clickConnectButton(); + + await loginPage.clickConnectWalletsBtnW3Modal(); + + await loginPage.clickWalletW3Modal("trust"); + expect(await loginPage.isWalletInfoInW3ModalDisplay("Trust Wallet")).toBeTruthy(); + await loginPage.clickBackBtnW3Modal(); + + await loginPage.clickWalletW3Modal("phantom"); + expect(await loginPage.isWalletInstallationW3ModalDisplay("Phantom")).toBeTruthy(); + await loginPage.clickBackBtnW3Modal(); + await loginPage.clickClosebtnW3Modal(); + + // OTHER TABS + await loginPage.selectChainNamespace("eip155"); + await loginPage.selectChain("0x1 Ethereum"); + await loginPage.selectAdapters(["coinbase-adapter", "torus-evm-adapter", "wallet-connect-v2-adapter", "injected-adapters"]); + + await loginPage.clickTab("WhiteLabel"); + await loginPage.clickConnectButton(); + await loginPage.clickConnectWalletsBtnW3Modal(); + expect(await loginPage.isAdapterListW3ModalDisplay()).toBeTruthy(); + + await loginPage.clickClosebtnW3Modal(); + + await loginPage.clickTab("Login Provider"); + await loginPage.selectLoginProvider("wechat"); + await loginPage.turnOnOffMainOption(); + await loginPage.turnOnOffonModal(); + await delay(2000); + await loginPage.clickConnectButton(); + await delay(5000); + expect((await page.$$("#w3a-modal .w3ajs-socials-adapters li")).length).toBe(1); + expect(await page.locator("#w3a-modal .w3ajs-socials-adapters button").getAttribute("title")).toBe("Wechat login"); + await loginPage.clickConnectWalletsBtnW3Modal(); + expect(await loginPage.isAdapterListW3ModalDisplay()).toBeTruthy(); + + await loginPage.clickClosebtnW3Modal(); + + await loginPage.clickTab(" Wallet Plugin "); + await loginPage.clickConnectButton(); + await loginPage.clickConnectWalletsBtnW3Modal(); + expect(await loginPage.isAdapterListW3ModalDisplay()).toBeTruthy(); + + await loginPage.clickClosebtnW3Modal(); + + await loginPage.clickTab(" Account Abstraction Provider "); + await loginPage.turnOnOffAccountAbstractionProvider(); + await loginPage.selectSmartAccountType("Safe"); + await loginPage.clickConnectButton(); + await loginPage.clickConnectWalletsBtnW3Modal(); + expect(await loginPage.isAdapterListW3ModalDisplay()).toBeTruthy(); + }); +});