Coder Social home page Coder Social logo

chainsafe / dappeteer Goto Github PK

View Code? Open in Web Editor NEW
487.0 13.0 150.0 17.44 MB

[DEPRECATED]๐ŸŒ๐Ÿผโ€E2E testing for dApps using Puppeteer + MetaMask

License: Other

JavaScript 0.54% HTML 4.71% TypeScript 94.64% Solidity 0.10%
pupeteer dapp e2e ethereum frontend arhived deprecated playwright

dappeteer's Introduction

Deprecation Notice

Notice: dAppeteer is deprecated and is no longer actively maintained. Due to ongoing changes in the MetaMask ecosystem and constraints in our resources, we have decided to discontinue development. This repository will remain available in a read-only, archived state.

Alternatives: We encourage users to explore the following alternatives, which provide continued support and active development for dApp testing:

We thank our community for the support and contributions over the years. For any additional questions or guidance on transitioning to new tools, please feel free to reach out.

Thank you for your understanding and collaboration.

dAppeteer

E2E testing for dApps using Puppeteer + MetaMask

Installation

$ npm install -s @chainsafe/dappeteer

or

$ yarn add @chainsafe/dappeteer

Usage

import dappeteer from '@chainsafe/dappeteer';

async function main() {
  const { metaMask, browser } = await dappeteer.bootstrap();

  // create a new page and visit your dapp
  const dappPage = await browser.newPage();
  await dappPage.goto('http://my-dapp.com');

  // you can change the network if you want
  await metaMask.switchNetwork('goerli');

  // do something in your dapp that prompts MetaMask to add a Token
  const addTokenButton = await dappPage.$('#add-token');
  await addTokenButton.click();
  // instruct MetaMask to accept this request
  await metaMask.acceptAddToken();

  // do something that prompts MetaMask to confirm a transaction
  const payButton = await dappPage.$('#pay-with-eth');
  await payButton.click();

  // ๐ŸŒ
  await metaMask.confirmTransaction();
}

main();

Usage with Snaps

import dappeteer from '@chainsafe/dappeteer';
import { exec } from "child_process";

async function buildSnap(): Promise<string> {
  console.log(`Building my-snap...`);
  await new Promise((resolve, reject) => {
    exec(`cd ./my-snap && npx mm-snap build`, (error, stdout) => {
      if (error) {
        reject(error);
        return;
      }
      resolve(stdout);
    });
  });

  return "./my-snap";
}

async function main() {
  // build your local snap
  const builtSnapDir = await buildSnap()

  // setup dappateer and install your snap
  const { metaMask, snapId, browser } = await dappeteer.initSnapEnv({
    snapIdOrLocation: builtSnapDir,
  });

  // you need to have a webpage open to interact with MetaMask, you can also visit a dApp page
  const dappPage = await browser.newPage();
  await dappPage.goto('http://example.org/');

  // invoke a method from your snap that prompts users with approve/reject dialog
  await metaMask.snaps.invokeSnap(dappPage, snapId, "my-method")

  // instruct MetaMask to accept this request
  await metaMask.snaps.dialog.positive();

  // get the notification emitter and the promise that will receive the notifications
  const emitter = await metaMask.snaps.getNotificationEmitter();
  const notificationPromise = emitter.waitForNotification();

  // do something that prompts your snap to emit notifications
  await metaMask.snaps.invokeSnap(dappPage, snapId, "notify");

  // Make sure the notification promise has resolved
  await notificationPromise;

  // You can now read the snap notifications and run tests against them
  const notifications = await metaMask.snaps.getAllNotifications();
}

main();

dappeteer's People

Contributors

3794 avatar abarmat avatar bayological avatar beroburny avatar cazala avatar fleupold avatar fmiras avatar github-actions[bot] avatar irubido avatar killianh avatar kivutar avatar lionseal avatar lykhoyda avatar marijanabevanda avatar minheq avatar mojinet avatar mpetrunic avatar mrtenz avatar nicosantangelo avatar omahs avatar rekmarks avatar scottcanoni avatar tbaut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dappeteer's Issues

metamaskDownloader runs every single instantiation; api.github.com quota hit

Doing iterative development, running it inside of a container, etc... every single instantiation of dappeteer hits api.github.com. there does not seem to be a way to force a specific version or zipfile and SKIP all the metamaskDownloader stuff. I didn't realize how bad this was until my IP is blocked for a while due to hitting api.github so much.

API methods addNetwork() in combination with switchNetwork() seems not to work

Hi,

When I ran the following code, I can add a new network but cannot switch to it. Visually I see that the switchNetwork method call does not actually switch anything. Using some from the predefined list such as ropsten works perfectly fine.

Any help appreciated.

Thanks,
Oliver

P.S.: using latest dappeteer 2.0.4 downloaded today.

const puppeteer = require('puppeteer');
const dappeteer = require('@chainsafe/dappeteer');

async function main() {
  const browser = await dappeteer.launch(puppeteer);
  const metamask = await dappeteer.setupMetamask(browser);

  await metamask.addNetwork({
    networkName: 'BSC',
    rpc: 'https://bsc-dataseed1.binance.org/',
    chainId: 56,
    symbol: 'BNB',
    explorer: 'https://bscscan.com/',
  });

  await metamask.switchNetwork('BSC');

Btw, I can see the newly created network and can manually switch to it.

Create Account method

As there is a method to import a private key to Metamask in that case should be create account
image

cannot confirm transaction

the function confirmTransaction() does not work. It tried to click the confirm button but it does work. The transaction is still not confirmed and the confirm button still displays like not clicked.
Perhaps we need to wait some time before clicking confirm button as it worked when adding code to sleep 5 second and click again

Unable to dismiss "What's New" modal in Metamask

Describe the problem

After calling the approve() function, the window switches to Metamask. However, it displays a modal window for "What's New". I am unable to dismiss this. Has anyone experienced this? Or is there a way we can dismiss it automatically?

Screenshot 2021-11-05 at 4 55 26 PM

It ends up timing out:

Running tests on MetaMask version v10.1.1

/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:517
            const timeoutError = new Errors_js_1.TimeoutError(`waiting for ${options.title} failed: timeout ${options.timeout}ms exceeded`);
                                 ^

TimeoutError: waiting for selector `button.button.btn-primary` failed: timeout 30000ms exceeded
    at new WaitTask (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:517:34)
    at DOMWorld.waitForSelectorInPage (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:428:26)
    at Object.internalHandler.waitFor (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/QueryHandler.js:31:77)
    at DOMWorld.waitForSelector (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:321:29)
    at Frame.waitForSelector (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:924:51)
    at Page.waitForSelector (/Users/xxx/Documents/Work/olympus-frontend/node_modules/puppeteer/lib/cjs/puppeteer/common/Page.js:2359:33)
    at /Users/xxx/Documents/Work/olympus-frontend/node_modules/@chainsafe/dappeteer/dist/metamask/approve.js:17:31
    at Generator.next (<anonymous>)
    at fulfilled (/Users/xxx/Documents/Work/olympus-frontend/node_modules/@chainsafe/dappeteer/dist/metamask/approve.js:5:58)

System:

  • OS: MacOS
  • OS version: 12.0.1
  • NodeJs version: 17.0.1
  • dAppeteer version: 2.2.0
  • testing framework: none
  • testing framework version: none

Example Code

  await page.goto("http://localhost:3000/#/stake");

  await clickElement(page, ".connect-button");

  await metamask.approve();

  await metamask.reload();
  const metamaskPopup = await metamask.page.waitForSelector("button.popover-header__button");
  await metamaskPopup.click();

I've also tried:
await metamask.page.waitForSelector(".popover-header__button");
await metamask.page.waitForSelector("[title='Close']");

dappeteer undefined

Hi I had this import undefined issue on the original dappeteer, so then I found this fork but I'm still having the same issue.

I installed dappeteer and puppeteer with yarn add @nodefactory/dappeteer and yarn add puppeteer and yarn add -D @types/puppeteer.
I then proceeded to run this simple function, but it seems like the dappeteer import is undefined.

TypeError: Cannot read property 'launch' of undefined

My file: minting.ts

import puppeteer from "puppeteer";
import dappeteer from "dappeteer";

export async function run() {
  const browser = await dappeteer.launch(puppeteer);
  const metamask = await dappeteer.getMetamask(browser);

  await browser.close();
}
โฏ yarn -v
1.22.4
โฏ node -v
v12.13.0

Is there some kind of more information I can provide to help debug why this is?

addNetwork function doesn't work

Hi there,

Thanks for the fork. As you suggested, might be an alternative as the original repo doesn't seem to be maintained.

I tested and was able to open Metamask.

However, it seems the addNetwork() function doesn't work; it just timeouts:

UnhandledPromiseRejectionWarning: TimeoutError: waiting for selector .network-indicator failed: timeout 30000ms exceeded

Can't launch browser through dappeteer.launch(puppeteer) function

Describe the bug
Hi! I just can't launch the browser through dappeteer.launch(puppeteer) function. At the same time, no error messages could be logged in the console.

But the original puppeteer.launch({ headless: false }) function is working fine.

To Reproduce

  1. Installation
    npm install -s @chainsafe/dappeteer

  2. Creat the test.mjs file

  3. Run
    node test.mjs

The following code does not work:

"use strict";

import puppeteer from "puppeteer";
import dappeteer from "@chainsafe/dappeteer";

const main = async () => {
  const browser = await dappeteer.launch(puppeteer);
  console.log(browser);
}

main();

It can not launch the browser and there are no error messages. And the console.log(browser) was not executed.

The following code will start the browser properly.

"use strict";

import puppeteer from "puppeteer";
import dappeteer from "@chainsafe/dappeteer";

const main = async () => {
  const browser = await puppeteer.launch({ headless: false });
  console.log(browser);
}

main();

System:

  • OS: [window 10 pro x64]
  • OS version [21H1]
  • NodeJs version [16.10.0, 16.19.1]
  • dAppeteer version [2.1.0]

Error while downloading metamask

I'm using dappeteer with jest-puppeeteer for automation testing. Coming across this issue when launching the browser.
log:

            for (const result of data) {
                                 ^

TypeError: data is not iterable
    at IncomingMessage.<anonymous> (/node_modules/@chainsafe/dappeteer/dist/metamaskDownloader.js:94:34)
    at IncomingMessage.emit (node:events:406:35)
    at endReadableNT (node:internal/streams/readable:1329:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)

It doesn't occur everytime, sometimes it works

Crashing when Rate Limited

If you're rate limited by the API, it crashes when trying to parse JSON, instead of logging an error or throwing or handling it better.

If you go to line 61 (https://github.com/ChainSafe/dappeteer/blob/master/src/metamaskDownloader.ts#L61), and add a log, like:

console.log(body); 
for (const result of JSON.parse(body)) {
    console.log('This console.log is not seen ');

You get the output:

{"message":"API rate limit exceeded for <IP address>. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)","documentation_url":"https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"}

C:\Users\Kevin\Desktop\DappateerProject\node_modules\@chainsafe\dappeteer\dist\metamaskDownloader.js:87
            for (const result of JSON.parse(body)) {
                                      ^

TypeError: JSON.parse is not a function or its return value is not iterable```

Can't use Headless mode

When i call setupMetamask using headless mode, the function never ends. I don't have errors but i can't use it.

const browser = await dappeteer.launch(puppeteer, {
        metamaskVersion: 'v10.1.1',
        headless: true
});

console.log('Loading metamask...')
const metamask = await dappeteer.setupMetamask(browser);
console.log('logged !')
  • NodeJs version v16.8.0
  • dAppeteer version 2.2.0

Error: ENOENT: no such file or directory, mkdir '/var/task/bot/node_modules/@chainsafe/dappeteer/metamask/download

Hi,
Is it possible to somehow change the extraction directory where the download is done?

ERRROR Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"Error: ENOENT: no such file or directory, mkdir '/var/task/bot/node_modules/@chainsafe/dappeteer/metamask/download'","reason":{"errorType":"Error","errorMessage":"ENOENT: no such file or directory, mkdir '/var/task/bot/node_modules/@chainsafe/dappeteer/metamask/download'","code":"ENOENT","errno":-2,"

The fs we have is RO, where the node_modules are placed as it is already a bundled application
So, I think the file doesn't exist, because the download failed (and..there is no error saying about it)

Thanks

How do I get everything to shut down gracefully in Jest?

Describe the bug

I am running into an issue where my test suite passes successfully but then it won't exit. I am doing this in Jest and using the setup / teardown / environment suggested here. However, it's just hanging, which suggests that there's some open handle. Unfortunately, there are long standing issues with jest's --detectOpenHandles flag and it's not showing anything.

Any idea? Have others run into this?

Turning dappeteer into a puppeteer-extra plugin to enable stealth mode to avoid being blocked by Cloudflare

Problem: Sometimes dappeteer is detected and blocked by Cloudflare.

Solution: Turning dappeteer into a puppeteer-extra plugin enables it to work with puppeteer-extra-plugin-stealth, thus effectively solving this problem.

Question:

@BeroBurny

Hi, Bero. Thanks again for your time.

I just want to know if there is an easy and quick way to implement this feature? And do you have the time to implement it?

Thanks.

getMetamask

now getMetamask has confirmWelcomeScreen importAccount closeNotificationPage (propably shoud be prepareMetamask) what arent actually part of getting metamask and getting metamask methods

Tests failing

https://github.com/NodeFactoryIo/dappeteer/pull/12/checks?check_run_id=1903669097

  dappeteer
Starting ganache...
Ganache running at http://localhost:8545
Starting test server...
Server running at http://localhost:8080
Deploying test contract...
web3-shh package will be deprecated in version 1.3.5 and will no longer be supported.
web3-bzz package will be deprecated in version 1.3.5 and will no longer be supported.
Contract deployed at 0x0fC7E4bD0784Af9b444015557CDBdA05d9D4D46e
    โœ“ should be deployed, contract
    โœ“ should running, puppeteer
    โœ“ should open, metamask
    โœ“ should open, test page
    โœ“ should switch network, localhost (87ms)
    โœ“ should import private key (382ms)
    โœ“ should switch accounts (133ms)
    โœ“ should lock and unlock (368ms)
    โœ“ should connect to ethereum (1760ms)
    โœ“ should be able to sign (958ms)
    1) should change gas values
    test contract
      2) should confirm transaction
      3) should have increased count


  10 passing (1m)
  3 failing

  1) dappeteer
       should change gas values:
     TimeoutError: waiting for selector `#txSent` failed: timeout 30000ms exceeded
      at new WaitTask (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:505:34)
      at DOMWorld.waitForSelectorInPage (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:416:26)
      at Object.internalHandler.waitFor (node_modules/puppeteer/lib/cjs/puppeteer/common/QueryHandler.js:31:77)
      at DOMWorld.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:312:29)
      at Frame.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:842:51)
      at Page.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/Page.js:1285:33)
      at /home/runner/work/dappeteer/dappeteer/test/test.spec.ts:134:22
      at Generator.next (<anonymous>)
      at fulfilled (test/test.spec.ts:24:58)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

  2) dappeteer
       test contract
         should confirm transaction:
     TimeoutError: waiting for selector `.btn-primary` failed: timeout 30000ms exceeded
      at new WaitTask (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:505:34)
      at DOMWorld.waitForSelectorInPage (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:416:26)
      at Object.internalHandler.waitFor (node_modules/puppeteer/lib/cjs/puppeteer/common/QueryHandler.js:31:77)
      at DOMWorld.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/DOMWorld.js:312:29)
      at Frame.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:842:51)
      at Page.waitForSelector (node_modules/puppeteer/lib/cjs/puppeteer/common/Page.js:1285:33)
      at Object.<anonymous> (src/index.ts:153:58)
      at Generator.next (<anonymous>)
      at fulfilled (src/index.ts:5:58)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

  3) dappeteer
       test contract
         should have increased count:

      AssertionError [ERR_ASSERTION]: Counter does not match BEFORE: 0 AFTER: 0
      + expected - actual

      -0
      +1
      
      at /home/runner/work/dappeteer/dappeteer/test/test.spec.ts:126:20
      at Generator.next (<anonymous>)
      at fulfilled (test/test.spec.ts:24:58)
      at processTicksAndRejections (internal/process/task_queues.js:93:5)

Force user to select metamask version

As current if the user does not provide a version of metamask he wants to use, and in case of UI breaking change on metamask plugin can cause dappeteer to fail a test and we want to avoid this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.