Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6d500a0
feat: update locators and toggle fixtures to use with simulator
christopherferreira9 Jan 20, 2025
204229b
feat: use path aliases for readable imports, prepare MWC e2e tests
christopherferreira9 Jan 21, 2025
d535a16
feat: update run script and work in progress for the new test structure
christopherferreira9 Jan 22, 2025
2ee0d43
feat: extends path usage, creates the first tests for playground-next
christopherferreira9 Jan 22, 2025
805d800
feat: implements personalSign on the playground-next for e2e usage
christopherferreira9 Jan 22, 2025
a4cd6ca
feat: always display terminate to avoid flaky tests
christopherferreira9 Jan 22, 2025
62b0fac
feat: removes unecessary logs
christopherferreira9 Jan 22, 2025
0eb4d00
feat: work in progress
christopherferreira9 Jan 28, 2025
f2301f3
feat: updates the Utils package to allow to start the app with fixtures
christopherferreira9 Feb 5, 2025
f1d47f1
chore: updates koa to solve vulnerability
christopherferreira9 Mar 13, 2025
38850ac
chore: updates configs and adds a logger
christopherferreira9 Mar 14, 2025
df10a9d
Merge main into christopher/update-e2e-ios-simulator
christopherferreira9 Apr 23, 2025
6d5d9b9
chore: removes non needed references in the code
christopherferreira9 Apr 24, 2025
aa3d197
chore: fixes dependency list
christopherferreira9 Apr 24, 2025
ad48cdb
chore: removes unused page object models
christopherferreira9 May 5, 2025
3b08dcf
feat: adds context switching feature to improve flakiness
christopherferreira9 May 5, 2025
15dd914
feat: add new dapp requirements
christopherferreira9 May 5, 2025
d039ce1
feat: cleans wdio configs
christopherferreira9 May 5, 2025
2f2bef8
chore: updates locators
christopherferreira9 May 5, 2025
ff2d85a
chore: removes unused test dapp reference
christopherferreira9 May 5, 2025
bdb2422
feat: adds automatic context switching via helpers
christopherferreira9 May 6, 2025
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
2 changes: 1 addition & 1 deletion e2e/.dapps.env.example
Original file line number Diff line number Diff line change
@@ -1 +1 @@
DEVNEXT_DAPP_URL=http://192.111.111.111:3333/demo
METAMASK_TEST_DAPP_URL=http://192.111.111.111:3333
8 changes: 4 additions & 4 deletions e2e/.ios.env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
BUNDLE_ID=
DEVICE_NAME=
PLATFORM_VERSION=
APP_PATH=
AUTOMATION_NAME=
DEVICE_NAME=iPhone 16 Pro
PLATFORM_VERSION=18.2
APP_PATH=METAMASK_APP_PATH
AUTOMATION_NAME=XCUITest
DEVICE_UDID=

39 changes: 15 additions & 24 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### Node version

`nvm use 18`
`nvm use 20`

### Setup:

Expand All @@ -12,38 +12,29 @@

`export SRP=TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST`

### Env files needed:
## Create an iOS simulator and Android emulator

.ios.env:

- BUNDLE_ID=
- DEVICE_NAME=
- PLATFORM_VERSION=
- APP_PATH=
- AUTOMATION_NAME=
- DEVICE_UDID=
### Complete your platform related env files:
`cp .ios.env.example .ios.env`

.android.env:

- BUNDLE_ID=
- DEVICE_NAME=
- PLATFORM_VERSION=
- APP_PATH=
- AUTOMATION_NAME=
- APP_ACTIVITY=
`cp .android.env.example .android.env`

.dapps.env:
```
DEVNEXT_DAPP_URL=
WAGMI_TEST_DAPP_URL=
```

- REACT_DAPP_URL=
- TEST_DAPP_URL=
# iOS
### Create an iOS simulator

.env:
### Run tests on iOS:

- BROWSERSTACK_USERNAME=
- BROWSERSTACK_ACCESS_KEY=
`yarn test:ios:jssdk:e2e:local`

### Run tests:
### Run tests on Android:

`yarn test:ios`
`yarn test:android:jssdk:e2e:local`

#### Currently setup to run locally
28 changes: 28 additions & 0 deletions e2e/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
'@babel/preset-typescript',
],
plugins: [
[
'module-resolver',
{
root: ['.'],
alias: {
'@': './test',
'@util': './util',
'@specs': './test/specs',
'@screens': './src/screens',
'@fixtures': './src/fixtures',
},
},
],
],
};
72 changes: 37 additions & 35 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,52 @@
"name": "metamask-sdk-e2e",
"private": true,
"type": "commonjs",
"scripts": {
"test:ios:metamask-connector:e2e:local": "wdio run test/configs/local/wdio.ios.app.local.conf.ts --suite metamask_connector",
"test:ios:metamask-connector:e2e:browserstack": "wdio run test/configs/browserstack/wdio.ios.app.browserstack.conf.ts --suite metamask_connector",
"test:android:metamask-connector:e2e:local": "wdio run test/configs/local/wdio.android.app.local.conf.ts --suite metamask_connector",
"test:android:metamask-connector:e2e:browserstack": "wdio run test/configs/browserstack/wdio.android.app.browserstack.conf.ts --suite metamask_connector",
"setup": "yarn install",
"build": "tsc --build",
"clean": "yarn clean:reports && rm -rf node_modules",
"clean:reports": "rm -rf allure-results",
"clean:build": "tsc --build --clean",
"allow-scripts": ""
},
"devDependencies": {
"@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@metamask/eslint-config": "11.1.0",
"@metamask/eslint-config-nodejs": "11.1.0",
"@metamask/eslint-config-typescript": "11.1.0",
"@types/koa": "^2.13.12",
"@types/lodash.merge": "4.6.9",
"@types/module-alias": "^2.0.4",
"@typescript-eslint/eslint-plugin": "5.61.0",
"@typescript-eslint/parser": "5.61.0",
"@wdio/allure-reporter": "^8.11.0",
"@wdio/appium-service": "^9.2.1",
"@wdio/browserstack-service": "^9.1.2",
"@wdio/cli": "latest",
"@wdio/globals": "8.24.6",
"@wdio/local-runner": "latest",
"@wdio/mocha-framework": "latest",
"@wdio/spec-reporter": "latest",
"ts-node": "^10.9.1",
"allure-commandline": "2.23.0",
"appium-adb": "11.0.8",
"babel-plugin-module-resolver": "^5.0.2",
"dotenv": "16.0.3",
"eslint": "8.44.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-jsdoc": "46.4.3",
"eslint-plugin-prettier": "4.2.1",
"koa": "2.14.2",
"module-alias": "^2.2.3",
"prettier": "2.8.8",
"ts-node": "^10.9.2",
"typescript": "^4.9.5",
"wdio-wait-for": "^3.0.9"
},
"scripts": {
"test:android:jssdk:e2e:browserstack": "wdio run test/configs/browserstack/wdio.android.app.browserstack.conf.ts --suite web_dapp",
"test:ios:jssdk:e2e:browserstack": "wdio run test/configs/browserstack/wdio.ios.app.browserstack.conf.ts --suite web_dapp",
"test:ios:jssdk:e2e:local": "wdio run test/configs/local/wdio.ios.app.local.conf.ts --suite web_dapp",
"test:android:jssdk:e2e:local": "wdio run test/configs/local/wdio.android.app.local.conf.ts --suite web_dapp",
"setup": "yarn install",
"build": "tsc --build",
"clean": "yarn clean:reports && rm -rf node_modules",
"clean:reports": "rm -rf allure-results",
"clean:build": "tsc --build --clean",
"allow-scripts": ""
},
"dependencies": {
"@metamask/eslint-config": "^11.1.0",
"@metamask/eslint-config-nodejs": "^11.1.0",
"@metamask/eslint-config-typescript": "^11.1.0",
"@types/lodash.merge": "^4.6.9",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"@wdio/globals": "^8.24.6",
"allure-commandline": "^2.23.0",
"appium-adb": "^11.0.8",
"axios": "^1.6.2",
"dotenv": "^16.0.3",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^46.4.3",
"eslint-plugin-prettier": "^4.2.1",
"koa": "^2.14.2",
"prettier": "^2.8.8",
"webdriverio": "^9.2.1"
"wdio-wait-for": "^3.0.9",
"webdriverio": "9.2.1"
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import axios from 'axios';
import { FIXTURE_SERVER_URL } from '../../src/Constants';
import FixtureServer from './FixtureServer';
import { FixtureBuilder } from './FixtureBuilder';
import FixtureServer from '@fixtures/FixtureServer';
import { FixtureBuilder } from '@fixtures/FixtureBuilder';
import { FIXTURE_SERVER_URL } from '@util/Constants';

// checks if server has already been started
const isFixtureServerStarted = async () => {
try {
const response = await axios.get(FIXTURE_SERVER_URL);
return response.status === 200;
const response = await fetch(FIXTURE_SERVER_URL);
return response.ok;
} catch (error) {
return false;
}
Expand All @@ -22,10 +21,10 @@ export const loadFixture = async (
const state = fixture || new FixtureBuilder().build();
fixtureServer.loadJsonState(state);
// Checks if state is loaded
const response = await axios.get(FIXTURE_SERVER_URL);
const response = await fetch(FIXTURE_SERVER_URL);

// Throws if state is not properly loaded
if (response.status !== 200) {
if (!response.ok) {
throw new Error('Not able to load fixtures');
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Koa from 'koa';
import * as http from "http";
import { FIXTURE_SERVER_HOST, FIXTURE_SERVER_PORT } from '../../src/Constants';
import { FIXTURE_SERVER_HOST, FIXTURE_SERVER_PORT } from '@util/Constants';

const CURRENT_STATE_KEY = '__CURRENT__';
const DEFAULT_STATE_KEY = '__DEFAULT__';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChainablePromiseElement } from 'webdriverio';
import { METAMASK_APP_NAME_ANDROID } from '../../Constants';
import Gestures from '../../Gestures';
import { getSelectorForPlatform } from '../../Utils';
import { AndroidSelector } from '../../Selectors';
import { METAMASK_APP_NAME_ANDROID } from '@util/Constants';
import Gestures from '@util/Gestures';
import { getSelectorForPlatform } from '@util/Utils';
import { AndroidSelector } from '@util/Selectors';

class AndroidSettingsOpeningLinksScreen {
get openingLinksMetaMaskAppOption(): ChainablePromiseElement {
Expand Down
8 changes: 4 additions & 4 deletions e2e/src/screens/Android/AndroidSettingsScreen.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ChainablePromiseArray, ChainablePromiseElement } from 'webdriverio';

import { $$ } from '@wdio/globals';
import Gestures from '../../Gestures';
import { getSelectorForPlatform } from '../../Utils';
import Gestures from '@util/Gestures';
import { getSelectorForPlatform } from '@util/Utils';
import {
IS_RUNNING_IN_BROWSER_STACK,
METAMASK_APP_NAME_ANDROID,
} from '../../Constants';
import { AndroidSelector } from '../../Selectors';
} from '@util/Constants';
import { AndroidSelector } from '@util/Selectors';

class AndroidSettingsScreen {
get metaMaskQALinksButton(): ChainablePromiseElement {
Expand Down
60 changes: 24 additions & 36 deletions e2e/src/screens/Android/ChromeBrowserScreen.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ChainablePromiseElement } from 'webdriverio';
import { driver } from '@wdio/globals';
import { getSelectorForPlatform } from '../../Utils';
import { MobileBrowser } from '../interfaces/MobileBrowser';
import { AndroidSelector } from '../../Selectors';
import { Dapp } from '../interfaces/Dapp';
import { Browsers, WEB_DAPP_LOAD_ATTEMPTS } from '../../../src/Constants';
import { waitUntil } from 'webdriverio/build/commands/browser';
import { MobileBrowser } from '@screens/interfaces/MobileBrowser';
import { Dapp } from '@screens/interfaces/Dapp';
import { getSelectorForPlatform } from '@util/Utils';
import { AndroidSelector } from '@util/Selectors';
import { Browsers } from '@util/Constants';

class ChromeBrowserScreen implements MobileBrowser {
get urlAddressBar(): ChainablePromiseElement {
Expand Down Expand Up @@ -95,6 +94,8 @@ class ChromeBrowserScreen implements MobileBrowser {
await driver.activateApp(Browsers.CHROME);
}

await driver.setOrientation('PORTRAIT');

await this.urlAddressBar.waitForDisplayed({
timeout: 10000,
});
Expand All @@ -105,63 +106,50 @@ class ChromeBrowserScreen implements MobileBrowser {
await this.urlAddressBar.clearValue();
await this.urlAddressBar.setValue(address);
await driver.pressKeyCode(66);
}

await this.refreshPage();

// Wait for the page to start loading
await driver.pause(3000);

const isWebDappLoaded = async () => {
let retries = 20;
// TODO: refactor this to use the page object
let isConnectButtonDisplayed = await ((await pageObject.connectButton) as ChainablePromiseElement).isDisplayed();

while (!isConnectButtonDisplayed && retries > 0) {
// Waits for 2 seconds before checking again
await driver.pause(2000);
isConnectButtonDisplayed = await ((await pageObject.connectButton) as ChainablePromiseElement).isDisplayed();
retries--;
}
};

let attempts = 0;
}

while (!isWebDappLoaded() && attempts < WEB_DAPP_LOAD_ATTEMPTS) {
await this.refreshPage();
attempts++;
if (pageObject) {
// pageObject will be used to determine if the page was loaded successfully
// once new test cases are added
console.log('ChromeBrowserScreen.goToAddress:: PageObject is not null');
}

// await pageObject.terminate();
}

async tapSwitchTabsButton(): Promise<void> {
await (this.switchTabsButton).click();
await this.switchTabsButton.click();
}

async tapBrowserMoreOptionsButton(): Promise<void> {
await (this.browserMoreOptions).click();
await this.browserMoreOptions.click();
}

async tapCloseAllTabsButton(): Promise<void> {
await (this.closeAllTabsButton).click();
await this.closeAllTabsButton.click();
}

async tapConfirmCloseAllTabsButton(): Promise<void> {
await (this.confirmCloseAllTabsButton).click();
await this.confirmCloseAllTabsButton.click();
}

async tapNewTabButton(): Promise<void> {
await (this.newTabButton).click();
await this.newTabButton.click();
}

async refreshPage(): Promise<void> {
await (this.browserMoreOptions).click();
await this.browserMoreOptions.click();
if (await this.stopRefreshingButton.isDisplayed()) {
await this.stopRefreshingButton.click();
await this.browserMoreOptions.click();
}
await this.refreshButton.click();
await driver.pause(6000); // Wait for the page to refresh
}

async launchBrowser(): Promise<void> {
// TODO
}
}

const chromeBrowserScreen = new ChromeBrowserScreen();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChainablePromiseElement } from 'webdriverio';

import { getSelectorForPlatform } from '../../../Utils';
import { AndroidSelector } from '../../../Selectors';
import { getSelectorForPlatform } from '@util/Utils';
import { AndroidSelector } from '@util/Selectors';

class AndroidOpenWithComponent {
get openWithMetaMaskQA(): ChainablePromiseElement {
Expand Down
Loading
Loading