From 3042f092b1ac6c3b92fd88ac2ceab91644f230a7 Mon Sep 17 00:00:00 2001 From: Bernard Date: Fri, 28 Oct 2022 17:18:54 +0200 Subject: [PATCH 1/7] pair improvements --- src/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types.ts b/src/types.ts index 20fc6fd2..7b23e582 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,7 @@ import { Path } from "./setup/metaMaskDownloader"; import { InstallStep } from "./snap/install"; import { InstallSnapResult } from "./snap/types"; import { RECOMMENDED_METAMASK_VERSION } from "./index"; +import { InstallSnapResult } from "./snap/types"; declare global { interface Window { From ce979018285261be1900e02369cdf9c0a1df0779 Mon Sep 17 00:00:00 2001 From: Bernard Date: Fri, 28 Oct 2022 17:21:43 +0200 Subject: [PATCH 2/7] fix lint --- src/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types.ts b/src/types.ts index 7b23e582..20fc6fd2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,7 +7,6 @@ import { Path } from "./setup/metaMaskDownloader"; import { InstallStep } from "./snap/install"; import { InstallSnapResult } from "./snap/types"; import { RECOMMENDED_METAMASK_VERSION } from "./index"; -import { InstallSnapResult } from "./snap/types"; declare global { interface Window { From a0edd88f5b635506f402c82abbb413714bfc07d4 Mon Sep 17 00:00:00 2001 From: Anton Lykhoyda Date: Tue, 1 Nov 2022 16:59:59 +0100 Subject: [PATCH 3/7] feat: add notify Snap method --- test/flask/methods-snap/src/index.ts | 10 +++++++ test/flask/snaps.spec.ts | 40 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/test/flask/methods-snap/src/index.ts b/test/flask/methods-snap/src/index.ts index f8f0bf37..78763b0d 100644 --- a/test/flask/methods-snap/src/index.ts +++ b/test/flask/methods-snap/src/index.ts @@ -15,6 +15,16 @@ export const onRpcRequest: OnRpcRequestHandler = ({ origin, request }) => { }, ], }); + case "notify_inApp": + return wallet.request({ + method: "snap_notify", + params: [ + { + type: "inApp", + message: `Hello, in App notification`, + }, + ], + }); default: throw new Error("Method not found."); } diff --git a/test/flask/snaps.spec.ts b/test/flask/snaps.spec.ts index a09de11c..f6ee17ee 100644 --- a/test/flask/snaps.spec.ts +++ b/test/flask/snaps.spec.ts @@ -4,6 +4,7 @@ import * as dappeteer from "../../src"; import { TestContext } from "../constant"; import { Snaps } from "../deploy"; import { toUrl } from "../utils/utils"; +import { clickOnElement, openProfileDropdown } from "../../src/helpers"; function getSnapIdByName(testContext: TestContext, snapName: Snaps): string { return `local:${toUrl(testContext.snapServers[snapName].address())}`; @@ -97,5 +98,44 @@ describe("snaps", function () { expect(await invokeAction).to.equal(false); }); + + it("should invoke IN APP NOTIFICATION method and show text", async function (this: TestContext) { + await metamask.snaps.invokeSnap( + testPage, + getSnapIdByName(this, Snaps.METHODS_SNAP), + "notify_inApp" + ); + + await metamask.page.bringToFront(); + await openProfileDropdown(metamask.page); + await clickOnElement(metamask.page, "Notifications"); + + const notificationItem = await metamask.page.waitForSelector( + ".notifications__item" + ); + const notificationText = await notificationItem.$eval( + ".notifications__item__details__message", + (el) => el.textContent + ); + const unreadDot = await notificationItem.$eval( + ".notifications__item__unread-dot", + (el) => el.className + ); + + expect(notificationText).to.equal("Hello, in App notification"); + expect(unreadDot).to.equal("notifications__item__unread-dot unread"); + + await notificationItem.click(); + const notificationItemUpdated = await metamask.page.waitForSelector( + ".notifications__item" + ); + + expect( + await notificationItemUpdated.$eval( + ".notifications__item__unread-dot", + (el) => el.className + ) + ).to.equal("notifications__item__unread-dot"); + }); }); }); From d231900013d997e220b01e785271a638a268ce61 Mon Sep 17 00:00:00 2001 From: Anton Lykhoyda Date: Mon, 7 Nov 2022 12:30:58 +0100 Subject: [PATCH 4/7] Added getAllNotifications method --- src/metamask/index.ts | 3 +- src/snap/getAllNotifications.ts | 17 +++++++++ src/snap/index.ts | 1 + src/snap/types.ts | 2 ++ src/types.ts | 3 +- test/flask/methods-snap/snap.manifest.json | 2 +- test/flask/methods-snap/src/index.ts | 10 ++++++ test/flask/snaps.spec.ts | 41 ++++++---------------- 8 files changed, 46 insertions(+), 33 deletions(-) create mode 100644 src/snap/getAllNotifications.ts diff --git a/src/metamask/index.ts b/src/metamask/index.ts index e5f03fb4..90166e14 100644 --- a/src/metamask/index.ts +++ b/src/metamask/index.ts @@ -4,7 +4,7 @@ import { Dappeteer } from ".."; import { acceptDialog } from "../snap/acceptDialog"; import { rejectDialog } from "../snap/rejectDialog"; -import { installSnap, invokeSnap } from "../snap"; +import { getAllNotifications, installSnap, invokeSnap } from "../snap"; import { addNetwork } from "./addNetwork"; import { addToken } from "./addToken"; import { approve } from "./approve"; @@ -53,6 +53,7 @@ export const getMetaMask = (page: Page): Promise => { deleteNetwork: deleteNetwork(page), }, snaps: { + getAllNotifications: getAllNotifications(page), acceptDialog: acceptDialog(page), rejectDialog: rejectDialog(page), invokeSnap, diff --git a/src/snap/getAllNotifications.ts b/src/snap/getAllNotifications.ts new file mode 100644 index 00000000..c0a52270 --- /dev/null +++ b/src/snap/getAllNotifications.ts @@ -0,0 +1,17 @@ +import { Page } from "puppeteer"; +import { clickOnElement, openProfileDropdown } from "../helpers"; +import { NotificationList } from "./types"; + +export const getAllNotifications = + (page: Page) => async (): Promise => { + await page.bringToFront(); + await openProfileDropdown(page); + await clickOnElement(page, "Notifications"); + await page.waitForTimeout(300); + + return await page.$$eval( + ".notifications__item__details__message", + (elements) => + elements.map((element) => ({ message: element.textContent })) + ); + }; diff --git a/src/snap/index.ts b/src/snap/index.ts index 1bb795ca..a3529048 100644 --- a/src/snap/index.ts +++ b/src/snap/index.ts @@ -1,3 +1,4 @@ export { flaskOnly } from "./utils"; export { installSnap } from "./install"; export { invokeSnap } from "./invokeSnap"; +export { getAllNotifications } from "./getAllNotifications"; diff --git a/src/snap/types.ts b/src/snap/types.ts index 3e4de4c3..9001d4de 100644 --- a/src/snap/types.ts +++ b/src/snap/types.ts @@ -18,3 +18,5 @@ export interface InstallSnapResult { }; }; } + +export type NotificationList = { message: string }[]; diff --git a/src/types.ts b/src/types.ts index 20fc6fd2..3fbbdd96 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,7 +5,7 @@ import { Page, Serializable } from "puppeteer"; import { Path } from "./setup/metaMaskDownloader"; import { InstallStep } from "./snap/install"; -import { InstallSnapResult } from "./snap/types"; +import { InstallSnapResult, NotificationList } from "./snap/types"; import { RECOMMENDED_METAMASK_VERSION } from "./index"; declare global { @@ -80,6 +80,7 @@ export type Dappeteer = { deleteNetwork: (name: string) => Promise; }; snaps: { + getAllNotifications: () => Promise; invokeSnap: ( page: Page, snapId: string, diff --git a/test/flask/methods-snap/snap.manifest.json b/test/flask/methods-snap/snap.manifest.json index c9b3bbc1..0cda0f70 100644 --- a/test/flask/methods-snap/snap.manifest.json +++ b/test/flask/methods-snap/snap.manifest.json @@ -3,7 +3,7 @@ "description": "An example Snap written in TypeScript.", "proposedName": "Methods Snap\n", "source": { - "shasum": "BCwqoDyQltaL0dh0IrzN1A66D1jPMLAseJOHmqI1faU=", + "shasum": "lHBPubadQ9IHZuFZkp77Vp7lrnZFW0J0OcGZvrn3NHc=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/test/flask/methods-snap/src/index.ts b/test/flask/methods-snap/src/index.ts index 78763b0d..f99baf84 100644 --- a/test/flask/methods-snap/src/index.ts +++ b/test/flask/methods-snap/src/index.ts @@ -25,6 +25,16 @@ export const onRpcRequest: OnRpcRequestHandler = ({ origin, request }) => { }, ], }); + case "notify_inApp_update": + return wallet.request({ + method: "snap_notify", + params: [ + { + type: "inApp", + message: `Update notification`, + }, + ], + }); default: throw new Error("Method not found."); } diff --git a/test/flask/snaps.spec.ts b/test/flask/snaps.spec.ts index f6ee17ee..5dad5fac 100644 --- a/test/flask/snaps.spec.ts +++ b/test/flask/snaps.spec.ts @@ -4,7 +4,6 @@ import * as dappeteer from "../../src"; import { TestContext } from "../constant"; import { Snaps } from "../deploy"; import { toUrl } from "../utils/utils"; -import { clickOnElement, openProfileDropdown } from "../../src/helpers"; function getSnapIdByName(testContext: TestContext, snapName: Snaps): string { return `local:${toUrl(testContext.snapServers[snapName].address())}`; @@ -99,43 +98,25 @@ describe("snaps", function () { expect(await invokeAction).to.equal(false); }); - it("should invoke IN APP NOTIFICATION method and show text", async function (this: TestContext) { + it("should invoke IN APP NOTIFICATIONS and check for a text", async function (this: TestContext) { await metamask.snaps.invokeSnap( testPage, getSnapIdByName(this, Snaps.METHODS_SNAP), "notify_inApp" ); - - await metamask.page.bringToFront(); - await openProfileDropdown(metamask.page); - await clickOnElement(metamask.page, "Notifications"); - - const notificationItem = await metamask.page.waitForSelector( - ".notifications__item" - ); - const notificationText = await notificationItem.$eval( - ".notifications__item__details__message", - (el) => el.textContent - ); - const unreadDot = await notificationItem.$eval( - ".notifications__item__unread-dot", - (el) => el.className + // Metamask doesn't allow to invoke two notifications in a row, + // so some delay should persist before calling the next notification + await metamask.page.waitForTimeout(5000); + await metamask.snaps.invokeSnap( + testPage, + getSnapIdByName(this, Snaps.METHODS_SNAP), + "notify_inApp_update" ); - expect(notificationText).to.equal("Hello, in App notification"); - expect(unreadDot).to.equal("notifications__item__unread-dot unread"); - - await notificationItem.click(); - const notificationItemUpdated = await metamask.page.waitForSelector( - ".notifications__item" - ); + const notifications = await metamask.snaps.getAllNotifications(); - expect( - await notificationItemUpdated.$eval( - ".notifications__item__unread-dot", - (el) => el.className - ) - ).to.equal("notifications__item__unread-dot"); + expect(notifications[0].message).to.equal("Update notification"); + expect(notifications[1].message).to.equal("Hello, in App notification"); }); }); }); From 80d68e5afaf520e36eb3ef722fe5e02ff1ea9070 Mon Sep 17 00:00:00 2001 From: Anton Lykhoyda Date: Mon, 7 Nov 2022 15:10:25 +0100 Subject: [PATCH 5/7] go back after getting all notifications --- src/snap/getAllNotifications.ts | 9 +++++++-- test/flask/snaps.spec.ts | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/snap/getAllNotifications.ts b/src/snap/getAllNotifications.ts index c0a52270..56fbf066 100644 --- a/src/snap/getAllNotifications.ts +++ b/src/snap/getAllNotifications.ts @@ -8,10 +8,15 @@ export const getAllNotifications = await openProfileDropdown(page); await clickOnElement(page, "Notifications"); await page.waitForTimeout(300); - - return await page.$$eval( + const notificationList: NotificationList = await page.$$eval( ".notifications__item__details__message", (elements) => elements.map((element) => ({ message: element.textContent })) ); + const backButton = await page.waitForSelector( + ".notifications__header__title-container__back-button" + ); + + await backButton.click(); + return notificationList; }; diff --git a/test/flask/snaps.spec.ts b/test/flask/snaps.spec.ts index 5dad5fac..d09217d5 100644 --- a/test/flask/snaps.spec.ts +++ b/test/flask/snaps.spec.ts @@ -115,6 +115,9 @@ describe("snaps", function () { const notifications = await metamask.snaps.getAllNotifications(); + expect(metamask.page.url()).to.match( + /chrome-extension:\/\/[a-z]+\/home\.html#/i + ); expect(notifications[0].message).to.equal("Update notification"); expect(notifications[1].message).to.equal("Hello, in App notification"); }); From 0e513bd7d58cb05155a7f250321a99bbcde93a46 Mon Sep 17 00:00:00 2001 From: Marin Petrunic Date: Wed, 9 Nov 2022 13:03:23 +0100 Subject: [PATCH 6/7] remove timeout --- src/snap/getAllNotifications.ts | 2 +- test/flask/methods-snap/snap.manifest.json | 2 +- test/flask/methods-snap/src/index.ts | 36 ++++++++++------------ test/flask/snaps.spec.ts | 14 +-------- 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/snap/getAllNotifications.ts b/src/snap/getAllNotifications.ts index 56fbf066..215afb05 100644 --- a/src/snap/getAllNotifications.ts +++ b/src/snap/getAllNotifications.ts @@ -7,7 +7,7 @@ export const getAllNotifications = await page.bringToFront(); await openProfileDropdown(page); await clickOnElement(page, "Notifications"); - await page.waitForTimeout(300); + await page.waitForSelector(".notifications__item__details__message"); const notificationList: NotificationList = await page.$$eval( ".notifications__item__details__message", (elements) => diff --git a/test/flask/methods-snap/snap.manifest.json b/test/flask/methods-snap/snap.manifest.json index 0cda0f70..d30b5edb 100644 --- a/test/flask/methods-snap/snap.manifest.json +++ b/test/flask/methods-snap/snap.manifest.json @@ -3,7 +3,7 @@ "description": "An example Snap written in TypeScript.", "proposedName": "Methods Snap\n", "source": { - "shasum": "lHBPubadQ9IHZuFZkp77Vp7lrnZFW0J0OcGZvrn3NHc=", + "shasum": "xxu7kMfZ4zKgviSZ5K4gZKSDDGEYi2VqOK5bKAqoybo=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/test/flask/methods-snap/src/index.ts b/test/flask/methods-snap/src/index.ts index f99baf84..772789de 100644 --- a/test/flask/methods-snap/src/index.ts +++ b/test/flask/methods-snap/src/index.ts @@ -1,6 +1,9 @@ import { OnRpcRequestHandler } from "@metamask/snap-types"; -export const onRpcRequest: OnRpcRequestHandler = ({ origin, request }) => { +export const onRpcRequest: OnRpcRequestHandler = async ({ + origin, + request, +}) => { switch (request.method) { case "confirm": return wallet.request({ @@ -16,25 +19,18 @@ export const onRpcRequest: OnRpcRequestHandler = ({ origin, request }) => { ], }); case "notify_inApp": - return wallet.request({ - method: "snap_notify", - params: [ - { - type: "inApp", - message: `Hello, in App notification`, - }, - ], - }); - case "notify_inApp_update": - return wallet.request({ - method: "snap_notify", - params: [ - { - type: "inApp", - message: `Update notification`, - }, - ], - }); + { + await wallet.request({ + method: "snap_notify", + params: [ + { + type: "inApp", + message: `Hello, in App notification`, + }, + ], + }); + } + break; default: throw new Error("Method not found."); } diff --git a/test/flask/snaps.spec.ts b/test/flask/snaps.spec.ts index d09217d5..dbb9490b 100644 --- a/test/flask/snaps.spec.ts +++ b/test/flask/snaps.spec.ts @@ -104,22 +104,10 @@ describe("snaps", function () { getSnapIdByName(this, Snaps.METHODS_SNAP), "notify_inApp" ); - // Metamask doesn't allow to invoke two notifications in a row, - // so some delay should persist before calling the next notification - await metamask.page.waitForTimeout(5000); - await metamask.snaps.invokeSnap( - testPage, - getSnapIdByName(this, Snaps.METHODS_SNAP), - "notify_inApp_update" - ); const notifications = await metamask.snaps.getAllNotifications(); - expect(metamask.page.url()).to.match( - /chrome-extension:\/\/[a-z]+\/home\.html#/i - ); - expect(notifications[0].message).to.equal("Update notification"); - expect(notifications[1].message).to.equal("Hello, in App notification"); + expect(notifications[0].message).to.equal("Hello, in App notification"); }); }); }); From e299bf649d7f62d22a599950eb0abd2e42bdd5c0 Mon Sep 17 00:00:00 2001 From: Marin Petrunic Date: Wed, 9 Nov 2022 13:33:06 +0100 Subject: [PATCH 7/7] fix post merge errors --- src/page.ts | 10 +++++++--- src/playwright/page.ts | 18 +++++++++++------- src/puppeteer/page.ts | 18 +++++++++++------- src/snap/getAllNotifications.ts | 4 ++-- test/global.ts | 1 + test/global_flask.ts | 1 + 6 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/page.ts b/src/page.ts index a4a003e1..525fe123 100644 --- a/src/page.ts +++ b/src/page.ts @@ -3,10 +3,14 @@ import { DappeteerElementHandle } from "./element"; export interface DappeteerPage

{ $(selector: string): Promise; - $eval( + $eval( selector: string, - evalFn: (e: HTMLElement) => Promise | void - ): Promise; + evalFn: (e: HTMLElement) => Promise | T + ): Promise; + $$eval( + selector: string, + evalFn: (e: HTMLElement[]) => Promise | T[] + ): Promise; $$(selector: string): Promise; getSource(): P; url(): string; diff --git a/src/playwright/page.ts b/src/playwright/page.ts index c0494ee5..bed3d5ee 100644 --- a/src/playwright/page.ts +++ b/src/playwright/page.ts @@ -23,14 +23,18 @@ export class DPlaywrightPage implements DappeteerPage { ); } - $eval( + $eval( selector: string, - evalFn: (e: HTMLElement) => void | Promise - ): Promise { - return this.page.$eval( - selector, - async (e) => await evalFn(e as HTMLElement) - ); + evalFn: (e: HTMLElement) => T | Promise + ): Promise { + return this.page.$eval(selector, evalFn); + } + + $$eval( + selector: string, + evalFn: (e: HTMLElement[]) => T[] | Promise + ): Promise { + return this.page.$$eval(selector, evalFn); } async $$(selector: string): Promise[]> { diff --git a/src/puppeteer/page.ts b/src/puppeteer/page.ts index e073d052..3d937253 100644 --- a/src/puppeteer/page.ts +++ b/src/puppeteer/page.ts @@ -21,14 +21,18 @@ export class DPupeteerPage implements DappeteerPage { return new DPuppeteerElementHandle(await this.page.$(selector)); } - $eval( + $eval( selector: string, - evalFn: (e: HTMLElement) => void | Promise - ): Promise { - return this.page.$eval( - selector, - async (e) => await evalFn(e as HTMLElement) - ); + evalFn: (e: HTMLElement) => T | Promise + ): Promise { + return this.page.$eval(selector, evalFn) as Promise; + } + + $$eval( + selector: string, + evalFn: (e: HTMLElement[]) => T[] | Promise + ): Promise { + return this.page.$$eval(selector, evalFn); } async $$(selector: string): Promise[]> { diff --git a/src/snap/getAllNotifications.ts b/src/snap/getAllNotifications.ts index 215afb05..1606eb51 100644 --- a/src/snap/getAllNotifications.ts +++ b/src/snap/getAllNotifications.ts @@ -1,9 +1,9 @@ -import { Page } from "puppeteer"; import { clickOnElement, openProfileDropdown } from "../helpers"; +import { DappeteerPage } from "../page"; import { NotificationList } from "./types"; export const getAllNotifications = - (page: Page) => async (): Promise => { + (page: DappeteerPage) => async (): Promise => { await page.bringToFront(); await openProfileDropdown(page); await clickOnElement(page, "Notifications"); diff --git a/test/global.ts b/test/global.ts index 75e69b70..f0e13394 100644 --- a/test/global.ts +++ b/test/global.ts @@ -12,6 +12,7 @@ import { deployContract, startLocalEthereum, startTestServer } from "./deploy"; export const mochaHooks = { async beforeAll(this: Mocha.Context): Promise { + this.timeout(100000); const ethereum = await startLocalEthereum({ wallet: { mnemonic: LOCAL_PREFUNDED_MNEMONIC, diff --git a/test/global_flask.ts b/test/global_flask.ts index b9a6ce98..fe859f39 100644 --- a/test/global_flask.ts +++ b/test/global_flask.ts @@ -15,6 +15,7 @@ import { export const mochaHooks = { async beforeAll(this: Mocha.Context): Promise { + this.timeout(100000); const ethereum = await startLocalEthereum({ wallet: { mnemonic: LOCAL_PREFUNDED_MNEMONIC,