diff --git a/package.json b/package.json index c3511705..325d4ded 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,8 @@ "solc": "0.5.2", "ts-node": "10.8.1", "typescript": "^4.7", - "web3": "1.3.4" + "web3": "1.3.4", + "web3-utils": "1.3.4" }, "peerDependencies": { "playwright": ">=1", diff --git a/src/metamask/confirmTransaction.ts b/src/metamask/confirmTransaction.ts index cbccb0f6..9cc4b08b 100644 --- a/src/metamask/confirmTransaction.ts +++ b/src/metamask/confirmTransaction.ts @@ -63,5 +63,9 @@ export const confirmTransaction = await clickOnButton(page, "Save"); } + + await page.waitForSelector( + '[data-testid="page-container-footer-next"]:not([disabled])' + ); await clickOnButton(page, "Confirm"); }; diff --git a/test/basic.spec.ts b/test/basic.spec.ts index e2ea7fb0..fa565f2a 100644 --- a/test/basic.spec.ts +++ b/test/basic.spec.ts @@ -2,9 +2,25 @@ import { expect, use } from "chai"; import chaiAsPromised from "chai-as-promised"; import * as dappeteer from "../src"; import { profileDropdownClick } from "../src/helpers"; -import { DappeteerPage } from "../src"; -import { PASSWORD, TestContext } from "./constant"; -import { clickElement } from "./utils/utils"; +import { DappeteerPage } from "../src/page"; + +import { + PASSWORD, + TestContext, + EXPECTED_MESSAGE_SIGNATURE, + ACCOUNT_ADDRESS, + MESSAGE_TO_SIGN, + EXPECTED_LONG_TYPED_DATA_SIGNATURE, + EXPECTED_SHORT_TYPED_DATA_SIGNATURE, +} from "./constant"; +import { + addNetwork, + addToken, + requestAccounts, + sign, + signLongTypedData, + signShortTypedData, +} from "./testPageFunctions"; use(chaiAsPromised); @@ -19,8 +35,9 @@ describe("basic interactions", function () { }); metamask = this.metamask; try { - await clickElement(testPage, ".connect-button"); + const connectionPromise = testPage.evaluate(requestAccounts); await metamask.approve(); + await connectionPromise; } catch (e) { //ignored } @@ -31,29 +48,34 @@ describe("basic interactions", function () { }); it("should be able to sign", async () => { - await clickElement(testPage, ".sign-button"); + const sigPromise = testPage.evaluate(sign, { + address: ACCOUNT_ADDRESS, + message: MESSAGE_TO_SIGN, + }); await metamask.sign(); - - await testPage.waitForSelector("#signed", { visible: false }); + const sig = await sigPromise; + expect(sig).to.be.equal(EXPECTED_MESSAGE_SIGNATURE); }); - it("should be able to sign typed data", async () => { - await clickElement(testPage, ".sign-typedData-button"); - + it("should be able to sign long typed data", async () => { + const sigPromise = testPage.evaluate(signLongTypedData, { + address: ACCOUNT_ADDRESS, + }); await metamask.signTypedData(); - await testPage.waitForSelector("#signed-typedData", { visible: false }); + const sig = await sigPromise; + expect(sig).to.be.equal(EXPECTED_LONG_TYPED_DATA_SIGNATURE); }); it("should be able to sign short typed data", async () => { - await clickElement(testPage, ".sign-short-typedData-button"); - + const sigPromise = testPage.evaluate(signShortTypedData, { + address: ACCOUNT_ADDRESS, + }); await metamask.signTypedData(); - await testPage.waitForSelector("#signed-short-typedData", { - visible: false, - }); + const sig = await sigPromise; + expect(sig).to.be.equal(EXPECTED_SHORT_TYPED_DATA_SIGNATURE); }); it("should switch network", async () => { @@ -81,27 +103,31 @@ describe("basic interactions", function () { }); it("should not add token", async () => { - await clickElement(testPage, ".add-token-button"); + const addTokenPromise = testPage.evaluate(addToken); await metamask.rejectAddToken(); - await testPage.waitForSelector("#addTokenResultFail"); + const res = await addTokenPromise; + expect(res).to.equal(false); }); it("should add token", async () => { - await clickElement(testPage, ".add-token-button"); + const addTokenPromise = testPage.evaluate(addToken); await metamask.acceptAddToken(); - await testPage.waitForSelector("#addTokenResultSuccess"); + const res = await addTokenPromise; + expect(res).to.equal(true); }); it("should not add network", async () => { - await clickElement(testPage, ".add-network-button"); + const addNetworkPromise = testPage.evaluate(addNetwork); await metamask.rejectAddNetwork(); - await testPage.waitForSelector("#addNetworkResultFail"); + const res = await addNetworkPromise; + expect(res).to.equal(false); }); it("should add network and switch", async () => { - await clickElement(testPage, ".add-network-button"); - await metamask.acceptAddNetwork(true); - await testPage.waitForSelector("#addNetworkResultSuccess"); + const addNetworkPromise = testPage.evaluate(addNetwork); + await metamask.acceptAddNetwork(); + const res = await addNetworkPromise; + expect(res).to.equal(true); }); it("should import private key", async () => { @@ -133,6 +159,18 @@ describe("basic interactions", function () { it("should lock and unlock", async () => { await metamask.lock(); + const pageTitle = await metamask.page.waitForSelector( + ".unlock-page__title" + ); + expect(pageTitle).to.not.be.undefined; + await metamask.unlock(PASSWORD); + const accountSwitcher = await metamask.page.waitForSelector( + ".account-menu__icon", + { + visible: true, + } + ); + expect(accountSwitcher).to.not.be.undefined; }); }); diff --git a/test/constant.ts b/test/constant.ts index f7e6977b..cb0ba80b 100644 --- a/test/constant.ts +++ b/test/constant.ts @@ -2,6 +2,7 @@ import http from "http"; import { Provider, Server } from "ganache"; +import web3 from "web3"; import { Dappeteer } from "../src"; import { DappeteerBrowser } from "../src/browser"; @@ -24,3 +25,12 @@ export type TestContext = Mocha.Context & InjectableContext; export const LOCAL_PREFUNDED_MNEMONIC = "pioneer casual canoe gorilla embrace width fiction bounce spy exhibit another dog"; export const PASSWORD = "password1234"; + +export const MESSAGE_TO_SIGN = web3.utils.sha3("TEST"); // "0x852daa74cc3c31fe64542bb9b8764cfb91cc30f9acf9389071ffb44a9eefde46"; +export const EXPECTED_MESSAGE_SIGNATURE = + "0x727c2e31ae342588b680dfc502f0d6a7b8d0f8b9afc4ca313bdad9dca80429741f50b78c2c98ac2f18c4ec1e8fade88c8d7477766d6ceeb1f3a3ddbe7d80e90f1c"; +export const EXPECTED_LONG_TYPED_DATA_SIGNATURE = + "0x26b713388823e1b9f91cb0064bdaa0a41b3728d35fd0f6bcfdd65900d27d20a21e3d207ded1a97f928c0f3eebdd709a950b353323f32080dad7db4fc8ff8222a1c"; +export const EXPECTED_SHORT_TYPED_DATA_SIGNATURE = + "0x66996a481e09815a4400be0988a28c53b357584b15f8dba6804050b8706d5b26645695436dca610fdb9a3ad052a2c35d890e60e8ed7f25beec531743b1aa583e1b"; +export const ACCOUNT_ADDRESS = "0x50707153077cFf1A48192311A12a5f905976AF14"; diff --git a/test/contract.spec.ts b/test/contract.spec.ts index 75f654ee..742bb6d1 100644 --- a/test/contract.spec.ts +++ b/test/contract.spec.ts @@ -1,11 +1,13 @@ import { expect } from "chai"; +import web3 from "web3"; import { Dappeteer } from "../src"; import { DappeteerPage } from "../src/page"; -import { TestContext } from "./constant"; +import { ACCOUNT_ADDRESS, TestContext } from "./constant"; +import { ContractInfo } from "./contract/contractInfo"; import { Contract } from "./deploy"; -import { clickElement } from "./utils/utils"; +import { requestAccounts, sendTx } from "./testPageFunctions"; describe("contract interactions", function () { let contract: Contract; @@ -14,13 +16,14 @@ describe("contract interactions", function () { before(async function (this: TestContext) { testPage = await this.browser.newPage(); - await testPage.goto("http://localhost:8080/", { waitUntil: "load" }); + await testPage.goto("http://localhost:8080/", { waitUntil: "networkidle" }); metamask = this.metamask; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment contract = this.contract; try { - await clickElement(testPage, ".connect-button"); + const connectionPromise = testPage.evaluate(requestAccounts); await metamask.approve(); + await connectionPromise; } catch (e) { //ignored } @@ -33,15 +36,31 @@ describe("contract interactions", function () { }); it("should have increased count", async () => { + const web3Instance = new web3(); + const counterContract = new web3Instance.eth.Contract(ContractInfo.abi); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + const contractData = counterContract.methods + .increase() + .encodeABI() as string; + + const txToSend = { + from: ACCOUNT_ADDRESS, + to: ContractInfo.address, + data: contractData, + }; + + const increasePromise = testPage.evaluate(sendTx, { + tx: txToSend, + }); + const counterBefore = await getCounterNumber(contract); - // click increase button - await clickElement(testPage, ".increase-button"); - // submit tx await metamask.confirmTransaction(); - await testPage.waitForSelector("#txSent", { visible: false }); - const counterAfter = await getCounterNumber(contract); + const tx = await increasePromise; + expect(tx).to.not.be.undefined; + const counterAfter = await getCounterNumber(contract); expect(counterAfter).to.be.equal(counterBefore + 1); }); }); diff --git a/test/contract/contractInfo.ts b/test/contract/contractInfo.ts new file mode 100644 index 00000000..370622b6 --- /dev/null +++ b/test/contract/contractInfo.ts @@ -0,0 +1,68 @@ +import { AbiItem } from "web3-utils"; + +export const ContractInfo = { + abi: [ + { + constant: true, + inputs: [], + name: "count", + outputs: [ + { + name: "", + type: "uint256", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x06661abd", + }, + { + constant: false, + inputs: [], + name: "increase", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + ] as AbiItem[], + evm: { + bytecode: { + linkReferences: {}, + object: + "608060405234801561001057600080fd5b5060bd8061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610604f576000357c01000000000000000000000000000000000000000000000000000000009004806306661abd146054578063e8927fbc146070575b600080fd5b605a6078565b6040518082815260200191505060405180910390f35b6076607e565b005b60005481565b600080815480929190600101919050555056fea165627a7a72305820fc33f994f18ba4440c94570ea658ed551e4c9914f16ddfae05477a898ea71e410029", + opcodes: + "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xBD DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x4F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV DUP1 PUSH4 0x6661ABD EQ PUSH1 0x54 JUMPI DUP1 PUSH4 0xE8927FBC EQ PUSH1 0x70 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x5A PUSH1 0x78 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x76 PUSH1 0x7E JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD DUP2 JUMP JUMPDEST PUSH1 0x0 DUP1 DUP2 SLOAD DUP1 SWAP3 SWAP2 SWAP1 PUSH1 0x1 ADD SWAP2 SWAP1 POP SSTORE POP JUMP INVALID LOG1 PUSH6 0x627A7A723058 KECCAK256 0xfc CALLER 0xf9 SWAP5 CALL DUP12 LOG4 DIFFICULTY 0xc SWAP5 JUMPI 0xe 0xa6 PC 0xed SSTORE 0x1e 0x4c SWAP10 EQ CALL PUSH14 0xDFAE05477A898EA71E4100290000 ", + sourceMap: "33:109:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33:109:0;;;;;;;", + }, + }, + address: "0x0fC7E4bD0784Af9b444015557CDBdA05d9D4D46e", + jsonInterface: [ + { + constant: true, + inputs: [], + name: "count", + outputs: [ + { + name: "", + type: "uint256", + }, + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x06661abd", + }, + { + constant: false, + inputs: [], + name: "increase", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + signature: "0xe8927fbc", + }, + ], +}; diff --git a/test/dapp/index.html b/test/dapp/index.html index c8176b0c..b2b40a8a 100644 --- a/test/dapp/index.html +++ b/test/dapp/index.html @@ -6,22 +6,9 @@