Skip to content

Commit 9a3bb9d

Browse files
committed
✨ feat: Support multiple account connection
1 parent ba2a0dc commit 9a3bb9d

File tree

8 files changed

+83
-11
lines changed

8 files changed

+83
-11
lines changed

docs/api/classes/MetaMask.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,16 @@ Confirms a transaction request.
216216
### connectToDapp()
217217
218218
```ts
219-
connectToDapp(): Promise<void>
219+
connectToDapp(accounts?): Promise<void>
220220
```
221221
222-
Connects to the dapp using the currently selected account.
222+
Connects to the dapp using the currently selected accounts.
223+
224+
#### Parameters
225+
226+
| Parameter | Type | Description |
227+
|:-----------|:-----------|:---------------|
228+
| `accounts` | `string[]` | Accounts list. |
223229
224230
#### Returns
225231

docs/docs/guides/playwright.md

+17
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,23 @@ test('should connect wallet to dapp', async ({ context, page, extensionId, metam
113113
await expect(page.locator('#accounts')).toHaveText('0xdeadbeef')
114114
})
115115
```
116+
```typescript [basic.spec.ts]
117+
import { testWithMetaMask as test } from './testWithMetaMask';
118+
119+
const { expect } = test;
120+
121+
// The `MetaMask` instance is now available in the test context.
122+
test('should connect multiple wallets to dapp', async ({ context, page, extensionId, metamask }) => {
123+
await page.goto('/');
124+
125+
await page.locator('#connectButton').click();
126+
127+
await metamask.connectToDapp(['0xdeadbeef1', '0xdeadbeef2']);
128+
129+
await expect(page.locator('#accounts')).toHaveText('0xdeadbeef1,0xdeadbeef2');
130+
131+
});
132+
```
116133

117134
:::
118135

wallets/metamask/src/metamask.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,12 @@ export class MetaMask {
139139
/**
140140
* Connects to the dapp using the currently selected account.
141141
*/
142-
async connectToDapp() {
142+
async connectToDapp(accounts?: string[]) {
143143
if (!this.extensionId) {
144144
throw NO_EXTENSION_ID_ERROR
145145
}
146146

147-
await this.notificationPage.connectToDapp(this.extensionId)
147+
await this.notificationPage.connectToDapp(this.extensionId, accounts)
148148
}
149149

150150
/**
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,36 @@
1-
import type { Page } from '@playwright/test'
1+
import type { Locator, Page } from '@playwright/test'
22
import Selectors from '../selectors'
3+
import { allTextContents } from '../../../utils/allTextContents'
34

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

8-
// Click `Connect`.
13+
async function confirmConnection(notificationPage: Page) {
914
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()
15+
await notificationPage.locator(Selectors.ActionFooter.confirmActionButton).click()
16+
}
17+
18+
// By default, only the last account will be selected. If you want to select a specific account, pass `accounts` parameter.
19+
export async function connectToDapp(notificationPage: Page, accounts?: string[]) {
20+
if (accounts && accounts.length > 0) {
21+
// Wait for the accounts to be loaded as 'all()' doesnt not wait for the results - https://playwright.dev/docs/api/class-locator#locator-all
22+
// Additionally disable default account to reuse necessary delay
23+
await notificationPage
24+
.locator(Selectors.ConnectPage.accountOption)
25+
.locator(Selectors.ConnectPage.accountCheckbox)
26+
.last()
27+
.setChecked(false)
28+
29+
const accountLocators = await notificationPage.locator(Selectors.ConnectPage.accountOption).all()
30+
const accountNames = await allTextContents(accountLocators)
31+
32+
await selectAccounts(accounts, accountLocators, accountNames)
33+
}
34+
35+
await confirmConnection(notificationPage)
1036
}

wallets/metamask/src/pages/NotificationPage/page.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export class NotificationPage {
2222
this.page = page
2323
}
2424

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

28-
await connectToDapp(notificationPage)
28+
await connectToDapp(notificationPage, accounts)
2929
}
3030

3131
// TODO: Revisit this logic in the future to see if we can increase the performance by utilizing `Promise.race`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
accountOption: '.choose-account-list .choose-account-list__list .choose-account-list__account',
3+
accountCheckbox: `input.choose-account-list__list-check-box`
4+
}

wallets/metamask/src/pages/NotificationPage/selectors/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import ConnectPage from './connectPage'
12
import ActionFooter from './actionFooter'
23
import NetworkPage from './networkPage'
34
import PermissionPage from './permissionPage'
45
import SignaturePage from './signaturePage'
56
import TransactionPage from './transactionPage'
67

78
export default {
9+
ConnectPage,
810
ActionFooter,
911
SignaturePage,
1012
NetworkPage,

wallets/metamask/test/e2e/metamask/connectToDapp.spec.ts

+17
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,20 @@ test('should connect wallet to dapp', async ({ context, page, extensionId }) =>
1818

1919
await expect(page.locator('#accounts')).toHaveText('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
2020
})
21+
22+
test('should connect multiple wallets to dapp', async ({ context, page, metamaskPage, extensionId }) => {
23+
const metamask = new MetaMask(context, metamaskPage, basicSetup.walletPassword, extensionId)
24+
25+
await metamask.addNewAccount('Account 2')
26+
await metamask.addNewAccount('Account 3')
27+
28+
await page.goto('/')
29+
await page.locator('#connectButton').click()
30+
31+
// "accounts" param is order agnostic
32+
await metamask.connectToDapp(['Account 2', 'Account 1'])
33+
34+
await expect(page.locator('#accounts')).toHaveText(
35+
'0x70997970c51812dc3a010c7d01b50e0d17dc79c8,0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'
36+
)
37+
})

0 commit comments

Comments
 (0)