Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"test:puppeteer:userData": "AUTOMATION=puppeteer yarn run test:userData",
"test:playwright:userData": "AUTOMATION=playwright yarn run test:userData",
"test:mm": "mocha --timeout 30000 --bail --require ts-node/register --require test/global.ts",
"test:kp": "mocha --timeout 30000 --bail --require ts-node/register --require test/keplr.ts",
"test:flask": "mocha --timeout 30000 --bail --require ts-node/register --require test/global_flask.ts",
"test:puppeteer:mm": "AUTOMATION=puppeteer yarn run test:mm",
"test:puppeteer:flask": "AUTOMATION=puppeteer yarn run test:flask",
Expand Down Expand Up @@ -82,8 +83,8 @@
"solc": "0.5.2",
"ts-node": "^10.9.1",
"typescript": "~4.7",
"web3": "4.0.1-alpha.2",
"web3-eth-contract": "4.0.1-alpha.2"
"web3": "^4.5.0",
"web3-eth-contract": "^4.2.0"
},
"peerDependencies": {
"playwright": ">=1.29",
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export {
launch,
setupMetaMask,
setupBootstrappedMetaMask,
} from "./setup";
} from "./setup/indexMetaMask";
export { DapeteerJestConfig } from "./jest/global";

// default constants
Expand Down
24 changes: 24 additions & 0 deletions src/setup/indexKeplr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DappeteerBrowser } from '../browser';
import { DappeteerLaunchOptions } from '../types';
import { launch } from './launchKeplr';
import { setupKeplr } from './setupKeplr';

export * from './launchMetaMask';
export * from './setupKeplr';

/**
* Launches browser and installs Keplr along with setting up initial account
*/
export const bootstrap = async ({
...launchOptions
}: DappeteerLaunchOptions): Promise<{
browser: DappeteerBrowser;
}> => {
const browser = await launch(launchOptions);
await new Promise((resolve) => setTimeout(resolve, 1000));
await setupKeplr(browser);

return {
browser,
};
};
5 changes: 3 additions & 2 deletions src/setup/index.ts → src/setup/indexMetaMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { DappeteerBrowser } from "../browser";
import { DappeteerPage } from "../page";
import { InstallSnapOptions } from "../snap/install";
import { Dappeteer, DappeteerLaunchOptions, MetaMaskOptions } from "../types";
import { launch } from "./launch";
import { launch } from "./launchMetaMask";
import { setupBootstrappedMetaMask, setupMetaMask } from "./setupMetaMask";

export * from "./launch";
export * from "./launchMetaMask";
export * from "./setupMetaMask";

/**
Expand All @@ -21,6 +21,7 @@ export const bootstrap = async ({
browser: DappeteerBrowser;
metaMaskPage: DappeteerPage;
}> => {
console.log("LAUNCHHHHHHHHHHHH", launchOptions)
const browser = await launch(launchOptions);
const metaMask = await (launchOptions.userDataDir
? setupBootstrappedMetaMask(browser, password)
Expand Down
29 changes: 29 additions & 0 deletions src/setup/launchKeplr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import fs from 'fs';
import { DappeteerBrowser } from '../browser';
import { DappeteerLaunchOptions } from '../types';
import { launchPuppeteer } from './puppeteer';
import { getTemporaryUserDataDir } from './utils/getTemporaryUserDataDir';
import downloader from './utils/keplrDownloader';

/**
* Launch Puppeteer chromium instance with Keplr plugin installed
* */
export async function launch(
options: DappeteerLaunchOptions = {}
): Promise<DappeteerBrowser> {
if (options.headless === undefined) {
options.headless = false;
}
let keplrPath: string;

keplrPath = await downloader();

const userDataDir = getTemporaryUserDataDir();

try {
return await launchPuppeteer(keplrPath, userDataDir, options);
} catch (error) {
fs.rmSync(userDataDir, { recursive: true, force: true });
throw new Error('Failed to launch puppeteer');
}
}
File renamed without changes.
101 changes: 101 additions & 0 deletions src/setup/setupActionsKeplr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {
keplrMnemonic,
keplrPassowrd,
keplrWalletName,
} from '../../test/constant';
import { getElementByContent } from '../helpers';
import { DappeteerPage } from '../page';

export async function importAccount(keplrPage: DappeteerPage): Promise<void> {
let importWalletButton = await getElementByContent(
keplrPage,
'Import an existing wallet'
);
await importWalletButton.click();

let recoveryPhraseButton = await getElementByContent(
keplrPage,
'Use recovery phrase or private key'
);
await recoveryPhraseButton.click();

let mnemonicButton = await getElementByContent(keplrPage, '24 words');
await mnemonicButton.click();

const passwordFields = await keplrPage.$$('input[type="password"]');
const words = keplrMnemonic.split(' ');

let index = 0;
for (const field of passwordFields) {
await field.type(words[index]);
index += 1;
}

const importButton = await keplrPage.waitForSelector(
'div.sc-bczRLJ.gclPdw button.sc-bZkfAO.jGdbNJ'
);
await importButton.click();

const walletNameField = await keplrPage.waitForSelector(
'input[placeholder="e.g. Trading, NFT Vault, Investment"].sc-iAvgwm.kEpgcC'
);
await walletNameField.click();
await walletNameField.type(keplrWalletName);

const passwordFieldSelector =
'input[name="password"][placeholder="At least 8 characters in length"].sc-iAvgwm.kEpgcC';
const confirmPasswordSelector =
'input[name="confirmPassword"][placeholder="At least 8 characters in length"].sc-iAvgwm.kEpgcC';

const passwordField = await keplrPage.$(passwordFieldSelector);
await passwordField.type(keplrPassowrd);

const confirmPasswordField = await keplrPage.$(confirmPasswordSelector);
await confirmPasswordField.type(keplrPassowrd);

let nextButton = await getElementByContent(keplrPage, 'Next');
await nextButton.click();
await new Promise((resolve) => setTimeout(resolve, 5000));

await keplrPage.evaluate(() => {
function containsText(element: Element, text: string): boolean {
if (element.textContent && element.textContent.includes(text)) {
return true;
}

for (let i = 0; i < element.children.length; i++) {
if (containsText(element.children[i], text)) {
return true;
}
}
return false;
}

const divs = document.querySelectorAll('div.sc-bczRLJ.eOeinv');
const divArray = Array.from(divs);

let targetDiv: Element | undefined;

for (let div of divArray) {
if (containsText(div, 'Agoric')) {
targetDiv = div;
break;
}
}

if (targetDiv) {
const checkboxes = targetDiv.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach((checkbox: Element) => {
(checkbox as HTMLInputElement).click();
});
}
});

let saveButton = await getElementByContent(keplrPage, 'Save');
await saveButton.click();

let finsihButton = await getElementByContent(keplrPage, 'Finish');
await finsihButton.click();

await new Promise((resolve) => setTimeout(resolve, 5000));
}
54 changes: 54 additions & 0 deletions src/setup/setupKeplr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { DappeteerBrowser } from '../browser';
import { DappeteerPage } from '../page';
import { importAccount } from './setupActionsKeplr';

const MM_HOME_REGEX = 'chrome-extension://[a-z]+/register.html#';

export async function setupKeplr(browser: DappeteerBrowser): Promise<void> {
const page = await getKeplrPage(browser);
await page.setViewport({ width: 1920, height: 1080 });
await importAccount(page);
}

async function getKeplrPage(
browser: DappeteerBrowser,
timeout: number = 10000
): Promise<DappeteerPage> {
try {
const pages = await browser.pages();
const keplrPage = pages.find((page) => page.url().match(MM_HOME_REGEX));
if (keplrPage) {
return keplrPage;
}

return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
browser.off('targetcreated', targetCreatedHandler);
reject(new Error('Timeout: Keplr page not found'));
}, timeout);

const targetCreatedHandler = async (target: any) => {
if (target.url().match(MM_HOME_REGEX)) {
clearTimeout(timeoutId);
try {
const pages = await browser.pages();
const keplrPage = pages.find((page) =>
page.url().match(MM_HOME_REGEX)
);
if (keplrPage) {
browser.off('targetcreated', targetCreatedHandler);
resolve(keplrPage);
}
} catch (e) {
browser.off('targetcreated', targetCreatedHandler);
reject(e);
}
}
};

browser.on('targetcreated', targetCreatedHandler);
});
} catch (error) {
throw new Error(`Failed to get Keplr page: ${error}`);
}
}
2 changes: 1 addition & 1 deletion src/setup/setupMetaMask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
enableEthSign,
importAccount,
showTestNets,
} from "./setupActions";
} from "./setupActionsMetaMask";

/**
* Setup MetaMask with base account
Expand Down
91 changes: 91 additions & 0 deletions src/setup/utils/keplrDownloader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
import * as fs from 'fs';
import { IncomingMessage } from 'http';
import { get } from 'https';
import * as path from 'path';

import StreamZip from 'node-stream-zip';

export const defaultDirectory = path.resolve(
'node_modules',
'.cache',
'.keplr'
);

export type Path =
| string
| {
download: string;
extract: string;
};

export default async (): Promise<string> => {
const keplrDirectory = defaultDirectory;
const downloadDirectory = path.resolve(defaultDirectory, 'download');

console.log(`extension stored in directory: ${keplrDirectory}`);
console.log(`downloaded files stored in: ${downloadDirectory}`, '\n');

const extractDestination = path.resolve(keplrDirectory);

if (!fs.existsSync(extractDestination)) {
let filename = 'keplr-extension-manifest-v2-v0.12.69.zip';
let downloadUrl =
'https://github.com/chainapsis/keplr-wallet/releases/download/v0.12.69/keplr-extension-manifest-v2-v0.12.69.zip';

const downloadedFile = await downloadKeplrReleases(
filename,
downloadUrl,
downloadDirectory
);
console.log('Unpacking release');
const zip = new StreamZip.async({ file: downloadedFile });
fs.mkdirSync(extractDestination);
console.log("extractdestination", {extractDestination})
await zip.extract(null, extractDestination);
console.log('Unpack successful');
} else {
console.log('Found already available extension files - skipping download');
}
return extractDestination;
};

const request = (url: string): Promise<IncomingMessage> =>
new Promise((resolve) => {
const request = get(url, (response) => {
if (response.statusCode == 302) {
const redirectRequest = get(response.headers.location, resolve);
redirectRequest.on('error', (error) => {
console.warn('request redirected error:', error.message);
throw error;
});
} else {
resolve(response);
}
});
request.on('error', (error) => {
console.warn('request error:', error.message);
throw error;
});
});

const downloadKeplrReleases = (
name: string,
url: string,
location: string
): Promise<string> =>
// eslint-disable-next-line no-async-promise-executor, @typescript-eslint/no-misused-promises
new Promise(async (resolve) => {
if (!fs.existsSync(location)) {
fs.mkdirSync(location, { recursive: true });
}
console.log('Downloading Keplr release');
const fileLocation = path.join(location, name);
const file = fs.createWriteStream(fileLocation);
const stream = await request(url);
stream.pipe(file);
stream.on('end', () => {
console.log('Download successful');
resolve(fileLocation);
});
});
2 changes: 1 addition & 1 deletion src/snap/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "../helpers";
import { DappeteerPage } from "../page";
import { EXAMPLE_WEBSITE } from "../constants";
import { closePrivacyWarningModal } from "../setup/setupActions";
import { closePrivacyWarningModal } from "../setup/setupActionsMetaMask";
import { startSnapServer, toUrl } from "./install-utils";
import { flaskOnly, isFirstElementAppearsFirst } from "./utils";
import { InstallSnapResult } from "./types";
Expand Down
6 changes: 5 additions & 1 deletion test/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Snaps, TestContract } from "./deploy";

export type InjectableContext = Readonly<{
provider: Provider;
ethereum: Server<"ethereum">;
ethereum: Server<any>;
snapServers?: Record<Snaps, string>;
browser: DappeteerBrowser;
metaMask: Dappeteer;
Expand All @@ -34,3 +34,7 @@ export const EXPECTED_SHORT_TYPED_DATA_SIGNATURE =
"0x66996a481e09815a4400be0988a28c53b357584b15f8dba6804050b8706d5b26645695436dca610fdb9a3ad052a2c35d890e60e8ed7f25beec531743b1aa583e1b";
export const ACCOUNT_ADDRESS = "0x50707153077cFf1A48192311A12a5f905976AF14";
export const SHORT_ACCOUNT_ADDRESS = "0x507...AF14";
export const keplrMnemonic =
'orbit bench unit task food shock brand bracket domain regular warfare company announce wheel grape trust sphere boy doctor half guard ritual three ecology';
export const keplrWalletName = "test-dev"
export const keplrPassowrd = "Test1234"
2 changes: 1 addition & 1 deletion test/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function getCounterContract(): { address: string } | null {

export async function startLocalEthereum(
opts?: ServerOptions
): Promise<Server<"ethereum">> {
): Promise<Server<any>> {
console.log("Starting ganache...");
opts = opts ?? {};
const server = ganache.server({ ...opts, logging: { quiet: true } });
Expand Down
Loading