Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ee4a513

Browse files
authored
feat: upgrade metamask version to 24 (#264)
* adjust code for metamask version24 * Fix install flask snap * Fix install flask snap wip * code cleanup * code cleanup * fix * code improvements * code cleanup * fix lint * refactoring
1 parent 58d01f2 commit ee4a513

38 files changed

+677
-358
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"@chainsafe/eslint-config": "^1.0.0",
6161
"@ganache/console.log": "^0.2.0",
6262
"@jest/types": "^27.1.1",
63-
"@metamask/snap-types": "^0.22.0",
63+
"@metamask/snap-types": "^0.23.0",
6464
"@metamask/snaps-cli": "^0.22.0",
6565
"@rushstack/eslint-patch": "^1.2.0",
6666
"@types/chai": "^4.2.22",

src/constants.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getDappateerPath } from "./helpers/utils";
33

44
export const EXAMPLE_WEBSITE = "http://example.org";
55

6-
export const RECOMMENDED_METAMASK_VERSION = "v10.23.0";
6+
export const RECOMMENDED_METAMASK_VERSION = "v10.24.2";
77

88
export const DEFAULT_METAMASK_USERDATA = path.join(
99
getDappateerPath(),

src/helpers/actions.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DappeteerElementHandle } from "../element";
22
import { DappeteerPage } from "../page";
33
import {
44
getAccountMenuButton,
5+
getButton,
56
getElementByContent,
67
getInputByLabel,
78
getSettingsSwitch,
@@ -41,7 +42,7 @@ export const profileDropdownClick = async (
4142
timeout: 2000,
4243
});
4344
await accountSwitcher.click();
44-
await page.waitForSelector(".account-menu__accounts", {
45+
await page.waitForSelector(".account-menu", {
4546
hidden: expectToClose,
4647
timeout: 2000,
4748
});
@@ -70,19 +71,37 @@ export const clickOnElement = async (
7071
export const clickOnButton = async (
7172
page: DappeteerPage,
7273
text: string,
73-
options?: { timeout?: number; visible?: boolean }
74+
options?: {
75+
timeout?: number;
76+
visible?: boolean;
77+
}
7478
): Promise<void> => {
75-
const button = await getElementByContent(page, text, "button", options);
79+
const button = await getButton(page, text, options);
7680
await button.click();
7781
};
7882

83+
export const clickOnNavigationButton = async (
84+
metaMaskPage: DappeteerPage,
85+
text: string
86+
): Promise<void> => {
87+
const navigationButton = await getButton(metaMaskPage, text);
88+
await Promise.all([
89+
metaMaskPage.waitForNavigation(),
90+
navigationButton.click(),
91+
]);
92+
};
93+
7994
export const clickOnLogo = async (page: DappeteerPage): Promise<void> => {
8095
const header = await page.waitForSelector(".app-header__logo-container", {
8196
visible: true,
8297
});
8398
await header.click();
8499
};
85100

101+
export const goToHomePage = async (page: DappeteerPage): Promise<void> => {
102+
return await clickOnButton(page, "app-header-logo");
103+
};
104+
86105
/**
87106
*
88107
* @param page

src/helpers/selectors.ts

+20
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ export const getElementByContent = (
1414
...options,
1515
});
1616

17+
export const getElementByTestId = (
18+
page: DappeteerPage,
19+
testId: string
20+
): Promise<DappeteerElementHandle | null> =>
21+
page.waitForSelector(`[data-testid="${testId}"]`);
22+
1723
export const getInputByLabel = (
1824
page: DappeteerPage,
1925
text: string,
@@ -75,3 +81,17 @@ export const getAccountMenuButton = (
7581
page.waitForXPath(`//button[contains(@title,'Account options')]`, {
7682
visible: true,
7783
});
84+
85+
export const getButton = async (
86+
page: DappeteerPage,
87+
text: string,
88+
options?: {
89+
timeout?: number;
90+
visible?: boolean;
91+
}
92+
): Promise<DappeteerElementHandle> => {
93+
return await Promise.race([
94+
getElementByTestId(page, text),
95+
getElementByContent(page, text, "button", options),
96+
]);
97+
};

src/metamask/sign.ts

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export const sign =
2626

2727
await clickOnButton(page, "Sign");
2828

29+
await page.waitForSelector(".signature-request-warning__content");
30+
await clickOnButton(page, "Sign");
31+
2932
// wait for MM to be back in a stable state
3033
await page.waitForSelector(".app-header", {
3134
visible: true,

src/page.ts

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ export interface DappeteerPage<P = unknown> {
8686
callback: Function | { default: Function }
8787
): Promise<void>;
8888

89+
waitForNavigation(options?: { timeout: number });
90+
8991
type(
9092
selector: string,
9193
text: string,

src/playwright/browser.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class DPlaywrightBrowser
1919
super();
2020
this.browser.on("page", (page) => this.emit("targetcreated", page));
2121
}
22+
2223
wsEndpoint(): string {
2324
return "";
2425
}

src/playwright/page.ts

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ export class DPlaywrightPage implements DappeteerPage<Page> {
140140
return this.page.exposeFunction(name, <Function>callback);
141141
}
142142

143+
async waitForNavigation(options?: {
144+
timeout: number;
145+
}): Promise<Response | null> {
146+
return this.page.waitForNavigation(options);
147+
}
148+
143149
type(
144150
selector: string,
145151
text: string,

src/puppeteer/page.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Browser, ElementHandle, Page } from "puppeteer";
1+
import { Browser, ElementHandle, Page, WaitForOptions } from "puppeteer";
22
import { DappeteerBrowser } from "../browser";
33
import { DappeteerElementHandle } from "../element";
44
import { DappeteerPage, Response, Serializable, Unboxed } from "../page";
@@ -155,6 +155,10 @@ export class DPupeteerPage implements DappeteerPage<Page> {
155155
return this.page.exposeFunction(name, callback);
156156
}
157157

158+
async waitForNavigation(options: WaitForOptions): Promise<Response | null> {
159+
return this.page.waitForNavigation(options);
160+
}
161+
158162
type(
159163
selector: string,
160164
text: string,

src/setup/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export const initSnapEnv = async (
6161
showTestNets,
6262
});
6363
const metaMaskPage = metaMask.page;
64-
6564
const snapId = await metaMask.snaps.installSnap(snapIdOrLocation, opts);
6665

6766
return {

src/setup/playwright.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export async function launchPlaywright(
1717
headless: options.headless,
1818
args: [
1919
"--accept-lang=en",
20+
"--window-size=1920,1080",
2021
`--disable-extensions-except=${metamaskPath}`,
2122
`--load-extension=${metamaskPath}`,
2223
...(options.playwrightOptions?.args || []),

src/setup/puppeteer.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export async function launchPuppeteer(
1414
userDataDir,
1515
args: [
1616
"--accept-lang=en",
17+
"--window-size=1920,1080",
1718
`--disable-extensions-except=${metamaskPath}`,
1819
`--load-extension=${metamaskPath}`,
1920
...(options.puppeteerOptions?.args || []),

src/setup/setupActions.ts

+24-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {
22
clickOnButton,
33
clickOnElement,
44
clickOnLogo,
5+
clickOnNavigationButton,
56
clickOnSettingsSwitch,
67
openNetworkDropdown,
78
typeOnInputField,
9+
waitForOverlay,
810
} from "../helpers";
911
import { DappeteerPage } from "../page";
1012
import { MetaMaskOptions } from "../types";
@@ -42,22 +44,29 @@ export async function importAccount(
4244
password = "password1234",
4345
}: MetaMaskOptions
4446
): Promise<void> {
45-
await clickOnButton(metaMaskPage, "Import wallet");
47+
await clickOnButton(metaMaskPage, "onboarding-import-wallet");
48+
await clickOnButton(metaMaskPage, "metametrics-i-agree");
4649

4750
for (const [index, seedPart] of seed.split(" ").entries())
4851
await typeOnInputField(metaMaskPage, `${index + 1}.`, seedPart);
52+
await clickOnButton(metaMaskPage, "Confirm Secret");
4953

5054
await typeOnInputField(metaMaskPage, "New password", password);
5155
await typeOnInputField(metaMaskPage, "Confirm password", password);
5256

53-
// select checkbox "I have read and agree to the"
54-
const acceptTerms = await metaMaskPage.waitForSelector(
55-
".create-new-vault__terms-label"
56-
);
57-
await acceptTerms.click();
57+
// onboarding/create-password URL
58+
await clickOnButton(metaMaskPage, "create-password-terms");
59+
await clickOnNavigationButton(metaMaskPage, "create-password-import");
60+
await waitForOverlay(metaMaskPage);
61+
62+
// onboarding/completion URL
63+
await clickOnNavigationButton(metaMaskPage, "onboarding-complete-done");
5864

59-
await clickOnButton(metaMaskPage, "Import");
60-
await clickOnButton(metaMaskPage, "All done");
65+
// onboarding/pin-extension tab 1 URL
66+
await clickOnButton(metaMaskPage, "pin-extension-next");
67+
68+
// onboarding/pin-extension tab 2 URL
69+
await clickOnNavigationButton(metaMaskPage, "pin-extension-done");
6170
}
6271

6372
export const closePopup = async (page: DappeteerPage): Promise<void> => {
@@ -87,3 +96,10 @@ export const closeWhatsNewModal = async (
8796
await clickOnLogo(page);
8897
await page.waitForTimeout(333);
8998
};
99+
100+
export const closeNewModal = async (page: DappeteerPage): Promise<void> => {
101+
const closeButton = await page.$(
102+
".home__subheader-link--tooltip-content-header-button"
103+
);
104+
await closeButton.click();
105+
};

src/setup/setupMetaMask.ts

+16-13
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ import { getMetaMask } from "../metamask";
33
import { DappeteerPage } from "../page";
44
import { Dappeteer, MetaMaskOptions } from "../types";
55

6-
import { clickOnButton, retry, waitForOverlay } from "../helpers";
6+
import { retry, waitForOverlay } from "../helpers";
77
import {
88
acceptTheRisks,
9+
closeNewModal,
910
closePortfolioTooltip,
1011
closeWhatsNewModal,
11-
confirmWelcomeScreen,
12-
declineAnalytics,
1312
importAccount,
1413
showTestNets,
1514
} from "./setupActions";
@@ -21,15 +20,15 @@ type Step<Options> = (
2120
page: DappeteerPage,
2221
options?: Options
2322
) => void | Promise<void>;
23+
2424
const defaultMetaMaskSteps: Step<MetaMaskOptions>[] = [
25-
confirmWelcomeScreen,
26-
declineAnalytics,
2725
importAccount,
26+
closeNewModal,
2827
showTestNets,
29-
closePortfolioTooltip,
3028
closeWhatsNewModal,
3129
closeWhatsNewModal,
3230
];
31+
3332
const flaskMetaMaskSteps: Step<MetaMaskOptions>[] = [
3433
acceptTheRisks,
3534
importAccount,
@@ -41,17 +40,23 @@ const flaskMetaMaskSteps: Step<MetaMaskOptions>[] = [
4140

4241
const MM_HOME_REGEX = "chrome-extension://[a-z]+/home.html";
4342

43+
function getDefaultSteps(browser: DappeteerBrowser): Step<MetaMaskOptions>[] {
44+
if (browser.isMetaMaskFlask()) {
45+
return flaskMetaMaskSteps;
46+
}
47+
48+
return defaultMetaMaskSteps;
49+
}
50+
4451
export async function setupMetaMask<Options = MetaMaskOptions>(
4552
browser: DappeteerBrowser,
4653
options?: Options,
4754
steps?: Step<Options>[]
4855
): Promise<Dappeteer> {
4956
const page = await getMetaMaskPage(browser);
50-
steps = steps ?? defaultMetaMaskSteps;
51-
if (browser.isMetaMaskFlask()) {
52-
steps = flaskMetaMaskSteps;
53-
}
54-
await page.setViewport({ height: 1080, width: 1920 });
57+
steps = steps ?? getDefaultSteps(browser);
58+
59+
await page.setViewport({ width: 1920, height: 1080 });
5560
// goes through the installation steps required by MetaMask
5661
for (const step of steps) {
5762
await step(page, options);
@@ -75,8 +80,6 @@ export async function setupBootstrappedMetaMask(
7580
if (browser.isMetaMaskFlask()) await waitForOverlay(page);
7681
await retry(() => metaMask.unlock(password), 3);
7782

78-
if (browser.isMetaMaskFlask()) await clickOnButton(page, "No");
79-
8083
await waitForOverlay(page);
8184
return metaMask;
8285
}

src/snap/install.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ export const installSnap =
4242
const installAction = installPage.evaluate(
4343
({ snapId, version }: { snapId: string; version?: string }) =>
4444
window.ethereum.request<InstallSnapResult>({
45-
method: "wallet_enable",
46-
params: [
47-
{
48-
[`wallet_snap_${snapId}`]: {
49-
version: version ?? "latest",
50-
},
45+
method: "wallet_requestSnaps",
46+
params: {
47+
[snapId]: {
48+
version: version ?? "latest",
5149
},
52-
],
50+
},
5351
}),
5452
{ snapId: snapIdOrLocation, version: opts?.version }
5553
);
@@ -65,7 +63,9 @@ export const installSnap =
6563
});
6664

6765
if (isAskingForPermissions) {
68-
await clickOnButton(flaskPage, "Approve & install");
66+
await clickOnButton(flaskPage, "page-container-footer-next", {
67+
visible: false,
68+
});
6969

7070
const isShowingWarning = await isFirstElementAppearsFirst({
7171
selectorOrXpath1: ".popover-wrap.snap-install-warning",
@@ -75,7 +75,7 @@ export const installSnap =
7575

7676
if (isShowingWarning) {
7777
await flaskPage.waitForSelector(".checkbox-label", {
78-
visible: true,
78+
visible: false,
7979
});
8080
for await (const checkbox of await flaskPage.$$(".checkbox-label")) {
8181
await checkbox.click();
@@ -93,7 +93,7 @@ export const installSnap =
9393
const result = await installAction;
9494
await installPage.waitForTimeout(1000);
9595
await installPage.close({ runBeforeUnload: true });
96-
if (!(snapIdOrLocation in result.snaps)) {
96+
if (!(snapIdOrLocation in result)) {
9797
throw new Error("Failed to install snap");
9898
}
9999
snapServer.close();

src/snap/invokeSnap.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ export async function invokeSnap<
1111
params?: P
1212
): ReturnType<typeof window.ethereum.request<R>> {
1313
flaskOnly(page);
14+
1415
const result = await page.evaluate(
1516
async (opts: { snapId: string; method: string; params: Unboxed<P> }) => {
1617
try {
1718
return await window.ethereum.request<R>({
1819
method: "wallet_invokeSnap",
19-
params: [
20-
`${opts.snapId}`,
21-
{
20+
params: {
21+
request: {
2222
method: opts.method,
23-
params: opts.params,
2423
},
25-
],
24+
snapId: opts.snapId,
25+
},
2626
});
2727
} catch (e) {
2828
return e as Error;

0 commit comments

Comments
 (0)