Skip to content

Commit

Permalink
✨ feat: Support multiple account connection
Browse files Browse the repository at this point in the history
Signed-off-by: Mateusz Franczuk <[email protected]>
  • Loading branch information
matstyler committed Feb 9, 2024
1 parent ba2a0dc commit dbc77a9
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 11 deletions.
10 changes: 8 additions & 2 deletions docs/api/classes/MetaMask.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,16 @@ Confirms a transaction request.
### connectToDapp()
```ts
connectToDapp(): Promise<void>
connectToDapp(accounts?): Promise<void>
```
Connects to the dapp using the currently selected account.
Connects to the dapp using the currently selected accounts.
#### Parameters
| Parameter | Type | Description |
|:-----------|:-----------|:---------------|
| `accounts` | `string[]` | Accounts list. |
#### Returns
Expand Down
17 changes: 17 additions & 0 deletions docs/docs/guides/playwright.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,23 @@ test('should connect wallet to dapp', async ({ context, page, extensionId, metam
await expect(page.locator('#accounts')).toHaveText('0xdeadbeef')
})
```
```typescript [basic.spec.ts]
import { testWithMetaMask as test } from './testWithMetaMask';

const { expect } = test;

// The `MetaMask` instance is now available in the test context.
test('should connect multiple wallets to dapp', async ({ context, page, extensionId, metamask }) => {
await page.goto('/');

await page.locator('#connectButton').click();

await metamask.connectToDapp(['0xdeadbeef1', '0xdeadbeef2']);

await expect(page.locator('#accounts')).toHaveText('0xdeadbeef1,0xdeadbeef2');

});
```

:::

Expand Down
4 changes: 2 additions & 2 deletions wallets/metamask/src/metamask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,12 @@ export class MetaMask {
/**
* Connects to the dapp using the currently selected account.
*/
async connectToDapp() {
async connectToDapp(accounts?: string[]) {
if (!this.extensionId) {
throw NO_EXTENSION_ID_ERROR
}

await this.notificationPage.connectToDapp(this.extensionId)
await this.notificationPage.connectToDapp(this.extensionId, accounts)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
import type { Page } from '@playwright/test'
import type { Locator, Page } from '@playwright/test'
import Selectors from '../selectors'
import { allTextContents } from '../../../utils/allTextContents'

export async function connectToDapp(notificationPage: Page) {
// Click `Next`.
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()
async function selectAccounts(accountsToSelect: string[], accountLocators: Locator[], availableAccountNames: string[]) {
for (const account of accountsToSelect) {
const accountNameIndex = availableAccountNames.findIndex((name) => name.startsWith(account))
if (accountNameIndex < 0) throw new Error(`[ConnectToDapp] Account with name ${account} not found`)
await accountLocators[accountNameIndex]?.locator(Selectors.ConnectPage.accountCheckbox).check()
}
}

// Click `Connect`.
async function confirmConnection(notificationPage: Page) {
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()
}

// By default, only the last account will be selected. If you want to select a specific account, pass `accounts` parameter.
export async function connectToDapp(notificationPage: Page, accounts?: string[]) {
if (accounts && accounts.length > 0) {
// Wait for the accounts to be loaded as 'all()' doesnt not wait for the results - https://playwright.dev/docs/api/class-locator#locator-all
// Additionally disable default account to reuse necessary delay
await notificationPage
.locator(Selectors.ConnectPage.accountOption)
.locator(Selectors.ConnectPage.accountCheckbox)
.last()
.setChecked(false)

const accountLocators = await notificationPage.locator(Selectors.ConnectPage.accountOption).all()
const accountNames = await allTextContents(accountLocators)

await selectAccounts(accounts, accountLocators, accountNames)
}

await confirmConnection(notificationPage)
}
4 changes: 2 additions & 2 deletions wallets/metamask/src/pages/NotificationPage/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export class NotificationPage {
this.page = page
}

async connectToDapp(extensionId: string) {
async connectToDapp(extensionId: string, accounts?: string[]) {
const notificationPage = await getNotificationPageAndWaitForLoad(this.page.context(), extensionId)

await connectToDapp(notificationPage)
await connectToDapp(notificationPage, accounts)
}

// TODO: Revisit this logic in the future to see if we can increase the performance by utilizing `Promise.race`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
accountOption: '.choose-account-list .choose-account-list__list .choose-account-list__account',
accountCheckbox: 'input.choose-account-list__list-check-box'
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import ActionFooter from './actionFooter'
import ConnectPage from './connectPage'
import NetworkPage from './networkPage'
import PermissionPage from './permissionPage'
import SignaturePage from './signaturePage'
import TransactionPage from './transactionPage'

export default {
ActionFooter,
ConnectPage,
SignaturePage,
NetworkPage,
PermissionPage,
Expand Down
17 changes: 17 additions & 0 deletions wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,20 @@ test('should connect wallet to dapp', async ({ context, page, extensionId }) =>

await expect(page.locator('#accounts')).toHaveText('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
})

test('should connect multiple wallets to dapp', async ({ context, page, metamaskPage, extensionId }) => {
const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword, extensionId)

await metamask.addNewAccount('Account 2')
await metamask.addNewAccount('Account 3')

await page.goto('/')
await page.locator('#connectButton').click()

// "accounts" param is order agnostic
await metamask.connectToDapp(['Account 2', 'Account 1'])

await expect(page.locator('#accounts')).toHaveText(
'0x70997970c51812dc3a010c7d01b50e0d17dc79c8,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
)
})

0 comments on commit dbc77a9

Please sign in to comment.