From c98ca1bb5bb8a0d2a110bae6a896b27d539ac008 Mon Sep 17 00:00:00 2001 From: tomiir Date: Tue, 2 Apr 2024 13:46:38 -0300 Subject: [PATCH] fix: reset sa enabled networks (#2104) --- .github/workflows/ui_tests.yml | 2 +- apps/laboratory/tests/email.spec.ts | 5 ++ .../shared/fixtures/w3m-email-fixture.ts | 37 +---------- .../fixtures/w3m-smart-account-fixture.ts | 62 +++++-------------- .../tests/shared/pages/ModalPage.ts | 45 ++++++++++++++ .../tests/shared/pages/ModalWalletPage.ts | 9 +++ .../shared/validators/ModalWalletValidator.ts | 4 +- apps/laboratory/tests/smart-account.spec.ts | 22 ++++++- .../core/src/controllers/NetworkController.ts | 4 +- .../controllers/ConnectorController.test.ts | 6 +- .../controllers/NetworkController.test.ts | 15 ++++- packages/ethers/src/client.ts | 3 +- 12 files changed, 124 insertions(+), 90 deletions(-) diff --git a/.github/workflows/ui_tests.yml b/.github/workflows/ui_tests.yml index 6e147a59c9..be2ec2df6f 100644 --- a/.github/workflows/ui_tests.yml +++ b/.github/workflows/ui_tests.yml @@ -102,5 +102,5 @@ jobs: if: always() with: name: screenshots - path: ./apps/laboratory/screenshots/ + path: ./apps/laboratory/test-results/ retention-days: 7 diff --git a/apps/laboratory/tests/email.spec.ts b/apps/laboratory/tests/email.spec.ts index 7fbc7474e0..8b20538af1 100644 --- a/apps/laboratory/tests/email.spec.ts +++ b/apps/laboratory/tests/email.spec.ts @@ -43,3 +43,8 @@ testMEmail('it should switch network and sign', async ({ modalPage, modalValidat await modalPage.approveSign() await modalValidator.expectAcceptedSign() }) + +testMEmail('it should disconnect correctly', async ({ modalPage, modalValidator }) => { + await modalPage.disconnect() + await modalValidator.expectDisconnected() +}) diff --git a/apps/laboratory/tests/shared/fixtures/w3m-email-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-email-fixture.ts index 42800dbadb..257d05cf65 100644 --- a/apps/laboratory/tests/shared/fixtures/w3m-email-fixture.ts +++ b/apps/laboratory/tests/shared/fixtures/w3m-email-fixture.ts @@ -2,7 +2,6 @@ import { test as base } from '@playwright/test' import type { ModalFixture } from './w3m-fixture' import { ModalPage } from '../pages/ModalPage' import { ModalValidator } from '../validators/ModalValidator' -import { DeviceRegistrationPage } from '../pages/DeviceRegistrationPage' import { Email } from '../utils/email' const mailsacApiKey = process.env['MAILSAC_API_KEY'] @@ -17,43 +16,9 @@ export const testMEmail = base.extend({ await modalPage.load() const email = new Email(mailsacApiKey) - const tempEmail = email.getEmailAddressToUse(testInfo.parallelIndex) - await email.deleteAllMessages(tempEmail) - await modalPage.loginWithEmail(tempEmail) - - let messageId = await email.getLatestMessageId(tempEmail) - - if (!messageId) { - throw new Error('No messageId found') - } - let emailBody = await email.getEmailBody(tempEmail, messageId) - let otp = '' - if (email.isApproveEmail(emailBody)) { - const url = email.getApproveUrlFromBody(emailBody) - - await email.deleteAllMessages(tempEmail) - - const drp = new DeviceRegistrationPage(await context.newPage(), url) - drp.load() - await drp.approveDevice() - await drp.close() - - messageId = await email.getLatestMessageId(tempEmail) - - emailBody = await email.getEmailBody(tempEmail, messageId) - if (!email.isApproveEmail(emailBody)) { - otp = email.getOtpCodeFromBody(emailBody) - } - } - if (otp.length !== 7) { - // eslint-disable-next-line no-console - console.log('Getting the OTP code from body', { previousOtp: otp }) - otp = email.getOtpCodeFromBody(emailBody) - } - await modalPage.enterOTP(otp) - + await modalPage.emailFlow(tempEmail, context) await use(modalPage) }, modalValidator: async ({ modalPage }, use) => { diff --git a/apps/laboratory/tests/shared/fixtures/w3m-smart-account-fixture.ts b/apps/laboratory/tests/shared/fixtures/w3m-smart-account-fixture.ts index 5891eb81c6..4e09552833 100644 --- a/apps/laboratory/tests/shared/fixtures/w3m-smart-account-fixture.ts +++ b/apps/laboratory/tests/shared/fixtures/w3m-smart-account-fixture.ts @@ -1,9 +1,9 @@ import { test as base } from '@playwright/test' import type { ModalFixture } from './w3m-fixture' -import { DeviceRegistrationPage } from '../pages/DeviceRegistrationPage' import { Email } from '../utils/email' import { ModalWalletPage } from '../pages/ModalWalletPage' import { ModalWalletValidator } from '../validators/ModalWalletValidator' +import type { ModalPage } from '../pages/ModalPage' const mailsacApiKey = process.env['MAILSAC_API_KEY'] if (!mailsacApiKey) { @@ -11,51 +11,23 @@ if (!mailsacApiKey) { } // Test Modal + Smart Account -export const testModalSmartAccount = base.extend({ +export const testModalSmartAccount = base.extend({ library: ['wagmi', { option: true }], - modalPage: async ({ page, library, context }, use, testInfo) => { - const modalPage = new ModalWalletPage(page, library) - await modalPage.load() - - const email = new Email(mailsacApiKey) - - const tempEmail = email.getEmailAddressToUse(testInfo.parallelIndex) - - await email.deleteAllMessages(tempEmail) - await modalPage.loginWithEmail(tempEmail) - - let messageId = await email.getLatestMessageId(tempEmail) - - if (!messageId) { - throw new Error('No messageId found') - } - let emailBody = await email.getEmailBody(tempEmail, messageId) - let otp = '' - if (email.isApproveEmail(emailBody)) { - const url = email.getApproveUrlFromBody(emailBody) - - await email.deleteAllMessages(tempEmail) - - const drp = new DeviceRegistrationPage(await context.newPage(), url) - drp.load() - await drp.approveDevice() - await drp.close() - - messageId = await email.getLatestMessageId(tempEmail) - - emailBody = await email.getEmailBody(tempEmail, messageId) - if (!email.isApproveEmail(emailBody)) { - otp = email.getOtpCodeFromBody(emailBody) - } - } - if (otp.length !== 6) { - otp = email.getOtpCodeFromBody(emailBody) - } - await modalPage.enterOTP(otp) - await modalPage.switchNetwork('Sepolia') - await modalPage.page.waitForTimeout(1500) - await use(modalPage) - }, + modalPage: [ + async ({ page, library, context }, use, testInfo) => { + const modalPage = new ModalWalletPage(page, library) + await modalPage.load() + + const email = new Email(mailsacApiKey) + const tempEmail = email.getEmailAddressToUse(testInfo.parallelIndex) + + await modalPage.emailFlow(tempEmail, context) + await modalPage.switchNetwork('Sepolia') + await modalPage.page.waitForTimeout(1500) + await use(modalPage) + }, + { timeout: 90_000 } + ], modalValidator: async ({ modalPage }, use) => { const modalValidator = new ModalWalletValidator(modalPage.page) await use(modalValidator) diff --git a/apps/laboratory/tests/shared/pages/ModalPage.ts b/apps/laboratory/tests/shared/pages/ModalPage.ts index 0688d6c3b9..7f2ffcb751 100644 --- a/apps/laboratory/tests/shared/pages/ModalPage.ts +++ b/apps/laboratory/tests/shared/pages/ModalPage.ts @@ -3,6 +3,13 @@ import type { BrowserContext, Locator, Page } from '@playwright/test' import { expect } from '@playwright/test' import { BASE_URL } from '../constants' import { doActionAndWaitForNewPage } from '../utils/actions' +import { Email } from '../utils/email' +import { DeviceRegistrationPage } from './DeviceRegistrationPage' + +const mailsacApiKey = process.env['MAILSAC_API_KEY'] || '' +if (!mailsacApiKey) { + throw new Error('MAILSAC_API_KEY is not set') +} export type ModalFlavor = 'default' | 'siwe' | 'email' | 'wallet' @@ -52,6 +59,44 @@ export class ModalPage { return this.assertDefined(await qrCode.getAttribute('uri')) } + async emailFlow(emailAddress: string, context: BrowserContext): Promise { + await this.load() + + const email = new Email(mailsacApiKey) + + await email.deleteAllMessages(emailAddress) + await this.loginWithEmail(emailAddress) + + let messageId = await email.getLatestMessageId(emailAddress) + + if (!messageId) { + throw new Error('No messageId found') + } + let emailBody = await email.getEmailBody(emailAddress, messageId) + let otp = '' + if (email.isApproveEmail(emailBody)) { + const url = email.getApproveUrlFromBody(emailBody) + + await email.deleteAllMessages(emailAddress) + + const drp = new DeviceRegistrationPage(await context.newPage(), url) + drp.load() + await drp.approveDevice() + await drp.close() + + messageId = await email.getLatestMessageId(emailAddress) + + emailBody = await email.getEmailBody(emailAddress, messageId) + if (!email.isApproveEmail(emailBody)) { + otp = email.getOtpCodeFromBody(emailBody) + } + } + if (otp.replace(' ', '').length !== 6) { + otp = email.getOtpCodeFromBody(emailBody) + } + await this.enterOTP(otp) + } + async loginWithEmail(email: string) { await this.page.goto(this.url) // Connect Button doesn't have a proper `disabled` attribute so we need to wait for the button to change the text diff --git a/apps/laboratory/tests/shared/pages/ModalWalletPage.ts b/apps/laboratory/tests/shared/pages/ModalWalletPage.ts index 54314aa1af..ec299dafbe 100644 --- a/apps/laboratory/tests/shared/pages/ModalWalletPage.ts +++ b/apps/laboratory/tests/shared/pages/ModalWalletPage.ts @@ -1,4 +1,5 @@ /* eslint-disable no-await-in-loop */ +import { expect } from '@playwright/test' import type { Page } from '@playwright/test' import { ModalPage } from './ModalPage' @@ -29,4 +30,12 @@ export class ModalWalletPage extends ModalPage { await this.page.getByTestId('w3m-header-close').click() await this.page.waitForTimeout(2000) } + + override async disconnect(): Promise { + this.openSettings() + const disconnectBtn = this.page.getByTestId('disconnect-button') + await expect(disconnectBtn, 'Disconnect button should be visible').toBeVisible() + await expect(disconnectBtn, 'Disconnect button should be enabled').toBeEnabled() + await disconnectBtn.click({ force: true }) + } } diff --git a/apps/laboratory/tests/shared/validators/ModalWalletValidator.ts b/apps/laboratory/tests/shared/validators/ModalWalletValidator.ts index d3c6525aa4..ab6fa99f0d 100644 --- a/apps/laboratory/tests/shared/validators/ModalWalletValidator.ts +++ b/apps/laboratory/tests/shared/validators/ModalWalletValidator.ts @@ -12,7 +12,9 @@ const testEmailsEOAAddresses = [ '0x8cD2c90E98309FcdeEd2bA0FdaC050e0284D1fD6', '0x4446d7538f4CF5832604BE20535d954439Ff075d', '0xbC6996C993d358989743bC74082B046da9d4d8fb', - '0x1216ff6012bcFcBaDFb4691cF586702Af9482F8C' + '0x1216ff6012bcFcBaDFb4691cF586702Af9482F8C', + // Non-smart account enabled address + '0x26760E9EbAcD6f4C47c095E7fd544C5AC093a4E3' ] function formatAddress(address: string) { diff --git a/apps/laboratory/tests/smart-account.spec.ts b/apps/laboratory/tests/smart-account.spec.ts index fd4dbe2365..a1efa3a038 100644 --- a/apps/laboratory/tests/smart-account.spec.ts +++ b/apps/laboratory/tests/smart-account.spec.ts @@ -2,6 +2,8 @@ import { testModalSmartAccount } from './shared/fixtures/w3m-smart-account-fixtu import type { ModalWalletPage } from './shared/pages/ModalWalletPage' import type { ModalWalletValidator } from './shared/validators/ModalWalletValidator' +const NOT_ENABLED_SMART_ACCOUNT_INDEX = 10 + testModalSmartAccount.beforeEach(async ({ modalValidator }) => { await modalValidator.expectConnected() }) @@ -45,8 +47,26 @@ testModalSmartAccount( const walletModalValidator = modalValidator as ModalWalletValidator await walletModalPage.togglePreferredAccountType() - await walletModalPage.switchNetwork('Polygon') + await walletModalPage.switchNetwork('Avalanche') await walletModalPage.openSettings() await walletModalValidator.expectEoaAddress(testInfo.parallelIndex) } ) + +testModalSmartAccount( + 'it should use an eoa when disconnecting and connecting to a not enabled address', + async ({ modalPage, modalValidator, context }) => { + const walletModalPage = modalPage as ModalWalletPage + const walletModalValidator = modalValidator as ModalWalletValidator + + await walletModalPage.togglePreferredAccountType() + await walletModalPage.disconnect() + await walletModalPage.page.waitForTimeout(2500) + + await walletModalPage.emailFlow('web3modal-smart-account@mailsac.com', context) + await walletModalPage.switchNetwork('Sepolia') + await walletModalPage.openSettings() + + await walletModalValidator.expectEoaAddress(NOT_ENABLED_SMART_ACCOUNT_INDEX) + } +) diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts index dd239cc187..3a36944902 100644 --- a/packages/core/src/controllers/NetworkController.ts +++ b/packages/core/src/controllers/NetworkController.ts @@ -33,7 +33,8 @@ type StateKey = keyof NetworkControllerState // -- State --------------------------------------------- // const state = proxy({ supportsAllNetworks: true, - isDefaultCaipNetwork: false + isDefaultCaipNetwork: false, + smartAccountEnabledNetworks: [] }) // -- Controller ---------------------------------------- // @@ -141,6 +142,7 @@ export const NetworkController = { } state.approvedCaipNetworkIds = undefined state.supportsAllNetworks = true + state.smartAccountEnabledNetworks = [] }, showUnsupportedChainUI() { diff --git a/packages/core/tests/controllers/ConnectorController.test.ts b/packages/core/tests/controllers/ConnectorController.test.ts index d042c78fc7..468d22a1f9 100644 --- a/packages/core/tests/controllers/ConnectorController.test.ts +++ b/packages/core/tests/controllers/ConnectorController.test.ts @@ -17,7 +17,7 @@ const emailProvider = { const walletConnectConnector = { id: 'walletConnect', - explorerId: 'walletConnect', + explorerId: 'walletConnectId', type: 'WALLET_CONNECT' } as const const externalConnector = { id: 'external', type: 'EXTERNAL' } as const @@ -78,7 +78,7 @@ describe('ConnectorController', () => { it('should return the correct connector on getConnector', () => { ConnectorController.addConnector(zerionConnector) - expect(ConnectorController.getConnector('walletConnect', '')).toBe(undefined) + expect(ConnectorController.getConnector('walletConnectId', '')).toBe(walletConnectConnector) expect(ConnectorController.getConnector('', 'io.metamask.com')).toBe(metamaskConnector) expect(ConnectorController.getConnector(zerionConnector.id, '')).toBeUndefined() expect(ConnectorController.getConnector('unknown', '')).toBeUndefined() @@ -98,6 +98,7 @@ describe('ConnectorController', () => { walletConnectConnector, externalConnector, metamaskConnector, + zerionConnector, emailConnector ]) @@ -123,6 +124,7 @@ describe('ConnectorController', () => { walletConnectConnector, externalConnector, metamaskConnector, + zerionConnector, emailConnector, announcedConnector ]) diff --git a/packages/core/tests/controllers/NetworkController.test.ts b/packages/core/tests/controllers/NetworkController.test.ts index 6ca3a977d8..8f93b88d6e 100644 --- a/packages/core/tests/controllers/NetworkController.test.ts +++ b/packages/core/tests/controllers/NetworkController.test.ts @@ -34,7 +34,8 @@ describe('NetworkController', () => { expect(NetworkController.state).toEqual({ _client: NetworkController._getClient(), supportsAllNetworks: true, - isDefaultCaipNetwork: false + isDefaultCaipNetwork: false, + smartAccountEnabledNetworks: [] }) }) @@ -64,6 +65,7 @@ describe('NetworkController', () => { expect(NetworkController.state.caipNetwork).toEqual(undefined) expect(NetworkController.state.approvedCaipNetworkIds).toEqual(undefined) expect(NetworkController.state.requestedCaipNetworks).toEqual(requestedCaipNetworks) + expect(NetworkController.state.smartAccountEnabledNetworks).toEqual([]) }) it('should update state correctly on setDefaultCaipNetwork()', () => { @@ -78,4 +80,15 @@ describe('NetworkController', () => { expect(NetworkController.state.approvedCaipNetworkIds).toEqual(undefined) expect(NetworkController.state.requestedCaipNetworks).toEqual(requestedCaipNetworks) }) + + it('should check correctly if smart accounts are enabled on the network', () => { + NetworkController.setSmartAccountEnabledNetworks([1]) + expect(NetworkController.checkIfSmartAccountEnabled()).toEqual(true) + NetworkController.setSmartAccountEnabledNetworks([]) + expect(NetworkController.checkIfSmartAccountEnabled()).toEqual(false) + NetworkController.setSmartAccountEnabledNetworks([2]) + expect(NetworkController.checkIfSmartAccountEnabled()).toEqual(false) + NetworkController.setCaipNetwork({ id: 'eip155:2', name: 'Ethereum' }) + expect(NetworkController.checkIfSmartAccountEnabled()).toEqual(true) + }) }) diff --git a/packages/ethers/src/client.ts b/packages/ethers/src/client.ts index 5f0449a0d1..655823f0aa 100644 --- a/packages/ethers/src/client.ts +++ b/packages/ethers/src/client.ts @@ -257,9 +257,8 @@ export class Web3Modal extends Web3ModalScaffold { } else if (providerType !== ConstantsUtil.EMAIL_CONNECTOR_ID) { provider?.emit('disconnect') } else { - this.emailProvider?.disconnect() + await this.emailProvider?.disconnect() } - provider?.emit('disconnect') }, signMessage: async (message: string) => {