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

fix: selector issues, useless timeouts, reorganise tests #145

Merged
merged 24 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: "16"
- name: Install
run: yarn install --frozen-lockfile
Expand All @@ -26,7 +25,12 @@ jobs:
- name: Lint
run: yarn run lint
- name: Tests
run: xvfb-run --auto-servernum yarn run test
run: xvfb-run --auto-servernum yarn run test --timeout 50000
- uses: actions/upload-artifact@v3
if: always()
with:
name: debug_screenshots
path: ./*.png

maybe-release:
name: release
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ dist
/metamask
.idea
*.log
test/dapp/data.js
test/dapp/data.js
*.png
10 changes: 10 additions & 0 deletions .mocharc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
parallel: false
recursive: true
color: true
timeout: 20000
exit: true
require:
- 'ts-node/register'
- 'test/global.ts'
spec:
- 'test/**/*.spec.ts'
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"devDependencies": {
"@jest/types": "^27.1.1",
"@types/chai": "^4.2.22",
"@types/mocha": "^7.0.2",
"@types/mocha": "^9.1.1",
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.15.0",
"chai": "^4.3.4",
Expand All @@ -55,7 +55,7 @@
"eslint-plugin-prettier": "^3.3.1",
"ganache": "^7.4.3",
"jest-environment-node": "^27.1.1",
"mocha": "7.2.0",
"mocha": "^10.0.0",
"prettier": "^2.2.1",
"puppeteer": "14.0.0",
"serve-handler": "5.0.8",
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ElementHandle, Page } from 'puppeteer';

// TODO: change text() with '.';
export const getElementByContent = (page: Page, text: string, type = '*'): Promise<ElementHandle | null> =>
page.waitForXPath(`//${type}[contains(text(), '${text}')]`);
page.waitForXPath(`//${type}[contains(text(), '${text}')]`, { timeout: 20000 });

export const getInputByLabel = (
page: Page,
Expand Down
1 change: 0 additions & 1 deletion src/metamask/confirmTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,5 @@ export const confirmTransaction = (page: Page, getSingedIn: GetSingedIn, version

await clickOnButton(page, 'Save');
}

await clickOnButton(page, 'Confirm');
};
1 change: 1 addition & 0 deletions src/metamask/helpers/deleteAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const deleteAccount = (page: Page, version?: string) => async (accountNum
await openAccountDropdown(page);
await clickOnElement(page, 'Remove account');
await clickOnButton(page, 'Remove');
await page.reload();
};
6 changes: 4 additions & 2 deletions src/metamask/helpers/getTokenBalance.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Page } from 'puppeteer';

import { clickOnButton } from '../../helpers';

export const getTokenBalance = (page: Page) => async (tokenSymbol: string): Promise<number> => {
await page.bringToFront();
await page.waitForTimeout(1000);

await clickOnButton(page, 'Assets');
await page.waitForSelector('.asset-list-item__token-button');
const assetListItems = await page.$$('.asset-list-item__token-button');

for (let index = 0; index < assetListItems.length; index++) {
Expand Down
2 changes: 2 additions & 0 deletions src/metamask/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const sign = (page: Page, getSingedIn: GetSingedIn, version?: string) =>
if (!(await getSingedIn())) {
throw new Error("You haven't signed in yet");
}

await page.waitForTimeout(500);
await page.reload();

await clickOnButton(page, 'Sign');
Expand Down
2 changes: 1 addition & 1 deletion src/metamask/switchNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ export const switchNetwork = (page: Page, version?: string) => async (network =

const networkButton = (await page.$$('li.dropdown-menu-item'))[networkIndex];
await networkButton.click();

await page.reload();
await page.waitForXPath(`//*[text() = '${networkFullName}']`);
};
8 changes: 4 additions & 4 deletions src/setup/setupMetaMask.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Browser, Page } from 'puppeteer';
import { Browser, BrowserContext, Page } from 'puppeteer';

import { getMetaMask } from '../metamask';
import { Dappeteer, MetaMaskOptions } from '../types';
Expand All @@ -12,12 +12,12 @@ type Step<Options> = (page: Page, options?: Options) => void;
const defaultMetaMaskSteps: Step<MetaMaskOptions>[] = [confirmWelcomeScreen, importAccount, closePopup, showTestNets];

export async function setupMetaMask<Options = MetaMaskOptions>(
browser: Browser,
browser: Browser | BrowserContext,
options?: Options,
steps: Step<Options>[] = defaultMetaMaskSteps,
): Promise<Dappeteer> {
const page = await closeHomeScreen(browser);

page.setViewport({ height: 1200, width: 800 });
// goes through the installation steps required by MetaMask
for (const step of steps) {
await step(page, options);
Expand All @@ -26,7 +26,7 @@ export async function setupMetaMask<Options = MetaMaskOptions>(
return getMetaMask(page);
}

async function closeHomeScreen(browser: Browser): Promise<Page> {
async function closeHomeScreen(browser: Browser | BrowserContext): Promise<Page> {
return new Promise((resolve, reject) => {
browser.on('targetcreated', async (target) => {
if (target.url().match('chrome-extension://[a-z]+/home.html')) {
Expand Down
126 changes: 126 additions & 0 deletions test/basic.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { expect, use } from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { Page } from 'puppeteer';

import * as dappeteer from '../src';
import { clickOnLogo, openProfileDropdown } from '../src/helpers';

import { PASSWORD, TestContext } from './global';
import { clickElement } from './utils/utils';

use(chaiAsPromised);

describe('basic interactions', async function () {
let metamask: dappeteer.Dappeteer;
let testPage: Page;

before(async function (this: TestContext) {
testPage = await this.browser.newPage();
await testPage.goto('http://localhost:8080/', { waitUntil: 'networkidle0' });
metamask = this.metamask;
try {
await clickElement(testPage, '.connect-button');
await metamask.approve();
} catch (e) {
//ignored
}
});

after(async function () {
await testPage.close();
});

it('should be able to sign', async () => {
await clickElement(testPage, '.sign-button');

await metamask.sign();

await testPage.waitForSelector('#signed');
});

it('should switch network', async () => {
await metamask.switchNetwork('localhost');

const selectedNetwork = await metamask.page.evaluate(
() => (document.querySelector('.network-display > span:nth-child(2)') as HTMLSpanElement).innerHTML,
);
expect(selectedNetwork).to.be.equal('Localhost 8545');
});

it('should return eth balance', async () => {
await metamask.switchNetwork('localhost');
const tokenBalance: number = await metamask.helpers.getTokenBalance('ETH');
expect(tokenBalance).to.be.greaterThan(0);
});

it('should return 0 token balance when token not found', async () => {
const tokenBalance: number = await metamask.helpers.getTokenBalance('FARTBUCKS');
expect(tokenBalance).to.be.equal(0);
});

// TODO: cover more cases
it('should add token', async () => {
await metamask.switchNetwork('kovan');
await metamask.addToken({
tokenAddress: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa',
symbol: 'KAKI',
});
await metamask.switchNetwork('local');
});

it('should add network with required params', async () => {
await metamask.addNetwork({
networkName: 'Binance Smart Chain',
rpc: 'https://data-seed-prebsc-1-s1.binance.org:8545/',
chainId: 97,
symbol: 'BNB',
});

const selectedNetwork = await metamask.page.evaluate(
() => (document.querySelector('.network-display > span:nth-child(2)') as HTMLSpanElement).innerHTML,
);
expect(selectedNetwork).to.be.equal('Binance Smart Chain');
await metamask.switchNetwork('local');
});

it('should fail to add network with wrong chain ID', async () => {
await expect(
metamask.addNetwork({
networkName: 'Optimistic Ethereum Testnet Kovan',
rpc: 'https://kovan.optimism.io/',
chainId: 420,
symbol: 'KUR',
}),
).to.be.rejectedWith(SyntaxError);

await clickOnLogo(metamask.page);
});

it('should import private key', async () => {
const countAccounts = async (): Promise<number> => {
await openProfileDropdown(metamask.page);
const container = await metamask.page.$('.account-menu__accounts');
const count = (await container.$$('.account-menu__account')).length;
await openProfileDropdown(metamask.page);
return count;
};

const beforeImport = await countAccounts();
await metamask.importPK('4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b10');
const afterImport = await countAccounts();

expect(beforeImport + 1).to.be.equal(afterImport);
await metamask.helpers.deleteAccount(2);
});

it('should throw error on wrong key', async () => {
await expect(
metamask.importPK('4f3edf983ac636a65a$@!ce7c78d9aa706d3b113bce9c46f30d7d21715b23b10'),
).to.be.rejectedWith(SyntaxError);
});

it('should lock and unlock', async () => {
await metamask.lock();
await metamask.unlock(PASSWORD);
});
});
60 changes: 60 additions & 0 deletions test/contract.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { expect } from 'chai';
import { Page } from 'puppeteer';

import { Dappeteer } from '../src';

import { Contract } from './deploy';
import { TestContext } from './global';
import { clickElement, pause } from './utils/utils';

describe('contract interactions', async function () {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let contract: Contract;
let testPage: Page;
let metamask: Dappeteer;

before(async function (this: TestContext) {
testPage = await this.browser.newPage();
await testPage.goto('http://localhost:8080/', { waitUntil: 'load' });
metamask = this.metamask;
contract = this.contract;
try {
await clickElement(testPage, '.connect-button');
await metamask.approve();
} catch (e) {
//ignored
}
});

after(async function (this: TestContext) {
await testPage.close();
});

it('should have increased count', async () => {
await metamask.switchAccount(1);
await metamask.switchNetwork('local');
await pause(1);
const counterBefore = await getCounterNumber(contract);
// click increase button
await clickElement(testPage, '.increase-button');
await pause(1);
// submit tx
await metamask.confirmTransaction();
await testPage.waitForSelector('#txSent');
await pause(1);

const counterAfter = await getCounterNumber(contract);

expect(counterAfter).to.be.equal(counterBefore + 1);
await metamask.switchNetwork('main');
});
});

function getCounterNumber(contract): Promise<number> {
return contract.methods
.count()
.call()
.then((res) => {
return Number(res);
});
}
13 changes: 6 additions & 7 deletions test/dapp/main.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
async function start() {
const web3 = new Web3(window.web3.currentProvider);
let accounts = [];

const web3 = new Web3(window.ethereum);
console.log(web3);
const counterContract = new web3.eth.Contract(ContractInfo.abi, ContractInfo.address);

const increaseButton = document.querySelector('.increase-button');
increaseButton.addEventListener('click', async function () {
const accounts = await web3.eth.getAccounts();
await counterContract.methods.increase().send({ from: accounts[0] });
const txSent = document.createElement('div');
txSent.id = 'txSent';
Expand All @@ -14,7 +15,6 @@ async function start() {

const increaseFeesButton = document.querySelector('.increase-fees-button');
increaseFeesButton.addEventListener('click', async function () {
const accounts = await web3.eth.getAccounts();
await counterContract.methods.increase().send({ from: accounts[0] });
const txSent = document.createElement('div');
txSent.id = 'feesTxSent';
Expand All @@ -23,24 +23,23 @@ async function start() {

const connectButton = document.querySelector('.connect-button');
connectButton.addEventListener('click', async function () {
await ethereum.enable();
accounts = await web3.eth.requestAccounts();
const connected = document.createElement('div');
connected.id = 'connected';
document.body.appendChild(connected);
});

const signButton = document.querySelector('.sign-button');
signButton.addEventListener('click', async function () {
const accounts = await web3.eth.getAccounts();
await web3.eth.personal.sign('TEST', accounts[0]);
const message = web3.utils.sha3('TEST');
await web3.eth.sign(message, accounts[0]);
const signed = document.createElement('div');
signed.id = 'signed';
document.body.appendChild(signed);
});

const transferButton = document.querySelector('.transfer-button');
transferButton.addEventListener('click', async function () {
const accounts = await web3.eth.getAccounts();
await web3.eth.sendTransaction({ to: accounts[0], from: accounts[0], value: web3.utils.toWei('0.01') });
const transfer = document.createElement('div');
transfer.id = 'transferred';
Expand Down
75 changes: 74 additions & 1 deletion test/dapp/web3.min.js

Large diffs are not rendered by default.