Tauri Wallet Test

. Currently developed against a Linux machine
. POM design
. README.md states how to get up and running on Linux 
WIP - areas of focus inbound ->
. CI
. Test suite configuration
. Working on multiple platforms
. Improve selector selection to reduce fragility in the future
This commit is contained in:
Tommy
2021-10-15 17:05:00 +01:00
parent 5fb2c9d822
commit f683b9e770
23 changed files with 988 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
on: [ push ]
name: webdriverio tests for nym wallet
jobs:
test:
name: wallet tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Tauri dependencies
run: >
sudo apt-get update &&
sudo apt-get install -y
libgtk-3-dev
libgtksourceview-3.0-dev
webkit2gtk-4.0
libappindicator3-dev
webkit2gtk-driver
xvfb
- name: Rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy, rustfmt
- name: Node v16
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Build application
run : yarn run webpack:build & yarn run tauri:build
working-directory: ./
- name: Yarn install
run: yarn install
working-directory: webdriver/
- name: Install tauri-driver
uses: actions-rs/cargo@v1
with:
command: install
args: tauri-driver
- name: Launch tests
run: xvfb-run yarn test:login
working-directory: webdriver/
+4
View File
@@ -0,0 +1,4 @@
reports
node_modules
.vscode
.idea
+72
View File
@@ -0,0 +1,72 @@
<!--
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
SPDX-License-Identifier: Apache-2.0
-->
# Nym Tauri Wallet Webdriver testsuite
A webdriverio test suite implementation using tauri driver
with a page object model design. This project is to provide quick iterative feedback
on the UI of the tauri nym wallet.
Currently, tauri-driver is available to run on Windows and Linux machines.
## Installation prerequisites
* `Yarn`
* `NodeJS >= v16.8.0`
* `Rust & cargo >= v1.51`
* `tauri-driver`
* `That you have an existing mnemonic and you can login to the app`
* `Have the details listed below to provide the user-data.js file`
## Key Information
* Please read the instructions on the `nym/tauri-wallet/README.md` in the root of the project on how to build the application
* Please ensure you have the relevant Webdriver kits installed on your machine -
```
linux:
sudo apt-get install -y webkit2gtk-driver
```
```
windows:
download msedgedriver.exe from https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
```
please visit [Tauri Studio](https://tauri.studio/en/docs/usage/guides/webdriver/introduction), this will specify the additional drivers you need)
* The path to run the application is set in the `wdio.conf.js` which lives in the root directory
* Before running the suite you need to build the application and check that the application has
built successfully, if so, you will have an executable sitting in the target directory in `src-tauri/*/nym_wallet` (refer to point 1)
* The suite will not be able to detect elements on screen if you select a release build, however you can run tests against a release target
## Installation & usage
* `test excution happens inside /webdriver directory`
* `test data needs to be provided inside the user-data.js module`
* `check the wdio.conf.js to see the activities and path location of the binary`
```
example:
//mnemonic is a base64 enconded value, which is your 24 character passphrase, these values are for illustration purposes
{
"mnemonic" : "dGhpcyBpcyBhIHBhc3NwaHJhc2UK",
"punk_address" : "punk1f3dzkhmunma5ze5q952daxca6371989189",
"receiver_address" : "punk1p0ce82jxxglpmutvhq4mdwgcwf4avm5n1821982",
"amount_to_send" : "5",
"identity_key_to_delegate":"value",
"identity_key_to_delegate_gateway" : "value"
"delegate_amount" : "1"
}
```
* `yarn test:runall` - the first test run will take some time to spin up be patient
* You can run tests individually by passing through the script situated in the package.json for example `yarn test:delegate`
## Updates
Disclaimer: As this project is WIP, there's a lot due to be updated and modified. This is to get the project up and running.
Refactoring needs to take place in certain areas to reduce code duplication, tidying up selectors and improving performance, implement error handling
Configuration for happy path and non happy path (non bonded users needs to happen)
Currently this project has been dev'd against a Linux based OS, not currently tested against Windows.
+12
View File
@@ -0,0 +1,12 @@
module.exports = {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "14"
}
}
]
]
}
@@ -0,0 +1,29 @@
module.exports = {
//receivePage
"recievePageInformation" : "You can receive tokens by providing this address to the sender",
"receivePageHeaderText": "Receive Nym",
//sendPage
"sendPunk" : "Send PUNK",
//homePage
"homePageErrorMnemonic": "Error parsing bip39 mnemonic",
"homePageSignIn" : "Sign in",
"createOne" : "Create one",
//bondPage // unbondPage
"bondAlreadyNoded" : "Looks like you already have a mixnode bonded.",
"bondNodeHeaderText": "Bond a node or gateway",
"unbondNodeHeaderText" : "Unbond a mixnode or gateway",
"unbondMixNodeText": "Looks like you already have a mixnode bonded.",
//balancePage
//delegatePage // undelegatePage
"delegateHeaderText" : "Delegate to mixnode or gateway",
"nodeIdentityValidationText" : "identity is a required field",
"amountValidationText": "amount is a required field",
//"transferFeeAmount" : "A fee of 0.004375 PUNK will apply to this transaction",
"undelegateHeaderText" : "Undelegate from a mixnode or gateway",
"delegationComplete" : "Delegation complete"
}
@@ -0,0 +1,8 @@
module.exports = {
"mnemonic": "",
"punk_address": "",
"receiver_address": "",
"amount_to_send": "",
"identity_key_to_delegate": "",
"delegate_amount": ""
}
@@ -0,0 +1,38 @@
class Helpers {
//helper to decode mnemonic so plain 24 character passphrase isn't in sight albeit it is presented when ruunning the scripts
//maybe a show passphrase toggle button?
decodeBase = async (input) => {
var m = Buffer.from(input, 'base64').toString();
return m;
}
navigateAndClick = async (element) => {
await element.click();
}
scrollIntoView = async (element) => {
await element.scrollIntoView();
}
currentBalance = async (value) => {
return parseFloat(value.split(/\s+/)[0].toString()).toFixed(5);
}
//this can be better - todo (fix)
calculateFees = async (beforeBalance, transactionFee, amount) => {
const fee = transactionFee.split(/\s+/)[3].toString();
const currentBalance = beforeBalance.split(/\s+/)[0].toString();
//cast existing balance to decimal
const castCurrentBalance = parseFloat(parseFloat(currentBalance).toFixed(5));
const transCost = +parseFloat(parseFloat(fee).toFixed(5)) +
+parseFloat(parseFloat(amount));
return parseFloat(castCurrentBalance - transCost).toFixed(5);
}
}
module.exports = new Helpers()
+25
View File
@@ -0,0 +1,25 @@
{
"name": "tauri_nym_wallet",
"version": "1.0.0",
"private": false,
"license": "MIT",
"scripts": {
"test:runall": "wdio run wdio.conf.cjs",
"test:sendreceive": "wdio run wdio.conf.cjs --suite sendAndReceive",
"test:login": "wdio run wdio.conf.cjs --suite login",
"test:bond": "wdio run wdio.conf.cjs --suite bond",
"test:delegate": "wdio run wdio.conf.cjs --suite delegate",
"test:newaccounts": "wdio run wdio.conf.cjs --suite nonExsistingUser"
},
"dependencies": {
"@types/node": "^16.11.0",
"@wdio/cli": "^7.9.1",
"@zxing/browser": "^0.0.9"
},
"devDependencies": {
"@wdio/local-runner": "^7.14.1",
"@wdio/mocha-framework": "^7.14.1",
"@wdio/spec-reporter": "^7.14.1",
"wdio-chromedriver-service": "^7.2.2"
}
}
@@ -0,0 +1,62 @@
class WalletBond {
get header() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span.MuiTypography-root.MuiCardHeader-subheader.MuiTypography-subtitle1.MuiTypography-colorTextSecondary.MuiTypography-displayBlock");
}
get identityKey() {
return $("#identityKey");
}
get sphinxKey() {
return $("#sphinxKey");
}
get amountToBond() {
return $("#amount");
}
get hostInput() {
return $("#host")
}
get versionInput() {
return $("version");
}
get advancedOptions() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div.MuiFormControl-root.MuiFormControl-fullWidth > div:nth-child(1) > div > div:nth-child(8) > label > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-13.MuiCheckbox-root.MuiCheckbox-colorSecondary.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get selectAdvancedOptions() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div.MuiFormControl-root.MuiFormControl-fullWidth > div:nth-child(1) > div > div:nth-child(8) > label > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-7.MuiCheckbox-root.MuiCheckbox-colorSecondary.MuiIconButton-colorSecondary");
}
get mixPort() {
return $("#mixPort");
}
get verlocPort() {
return $("#verlocPort");
}
get httpApiPort() {
return $("#httpApiPort");
}
get bondButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div.MuiFormControl-root.MuiFormControl-fullWidth > div:nth-child(2) > button");
}
get unBondButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div.MuiAlert-action > button > span.MuiButton-label");
}
get unBondInformation(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div.MuiAlert-message");
}
}
module.exports = new WalletBond()
@@ -0,0 +1,79 @@
class WalletDelegate {
get header() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span.MuiTypography-root.MuiCardHeader-subheader.MuiTypography-subtitle1.MuiTypography-colorTextSecondary.MuiTypography-displayBlock")
}
get nodeIdentity() {
return $("#identity");
}
get accountBalance() {
return $("#root > div > div:nth-child(1) > div:nth-child(3) > div:nth-child(1) > div > div.MuiCardContent-root > div > div > h6");
}
get amountToDelegate() {
return $("#amount");
}
get identityValidation() {
return $("#identity-helper-text");
}
get amountToDelegateValidation() {
return $("#amount-helper-text");
}
get delegateStakeButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > button > span.MuiButton-label");
}
get mixNodeRadioButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(1) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-8.MuiRadio-root.MuiRadio-colorSecondary.PrivateSwitchBase-checked-9.Mui-checked.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get gateWayRadioButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(2) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-8.MuiRadio-root.MuiRadio-colorSecondary.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get transactionFeeAmount() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(2) > div > div.MuiAlert-message");
}
get successfullyDelegate() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div:nth-child(1) > div > div.MuiAlert-message > div");
}
get finishSuccessDelegation() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div:nth-child(2) > button");
}
//Undelegate
get unDelegateHeader(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span.MuiTypography-root.MuiCardHeader-subheader.MuiTypography-subtitle1.MuiTypography-colorTextSecondary.MuiTypography-displayBlock");
}
get unNodeIdentity(){
return $("#mui-52147");
}
get unDelegateFeeText(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(2) > div > div.MuiAlert-message");
}
get unDelegateGatewayRadioButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(2) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-8.MuiRadio-root.MuiRadio-colorSecondary.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get unMixNodeRadioButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(1) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-8.MuiRadio-root.MuiRadio-colorSecondary.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get unDelegateButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > button > span.MuiButton-label");
}
}
module.exports = new WalletDelegate()
@@ -0,0 +1,49 @@
class WalletHome {
get balanceCheck() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span");
}
get punkBalance() {
return $("#root > div > div:nth-child(1) > div:nth-child(3) > div:nth-child(1) > div > div.MuiCardContent-root > div > div > h6");
}
get punkAddress() {
return $("#root > div > div:nth-child(1) > div:nth-child(3) > div:nth-child(2) > div > div.MuiCardContent-root > div > p");
}
get sendButton() {
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(2) > div.MuiListItemText-root > span");
}
get receiveButton() {
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(3) > div.MuiListItemText-root > span");
}
get bondButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(4) > div.MuiListItemText-root > span");
}
get unBondButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(5) > div.MuiListItemText-root > span");
}
get delegateButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(6) > div.MuiListItemText-root > span");
}
get unDelegateButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(7) > div.MuiListItemText-root > span");
}
get docsButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > a:nth-child(8) > div.MuiListItemText-root > span");
}
get logOutButton(){
return $("#root > div > div:nth-child(1) > div:nth-child(4) > div > ul > div > div.MuiListItemText-root > span");
}
}
module.exports = new WalletHome()
@@ -0,0 +1,42 @@
class WalletLogin {
get signInLabel() {
return $("#root > div > div:nth-child(2) > div > h4");
}
get mnemonic() {
return $("#mnemonic");
}
get signInButton() {
return $("#root > div > div:nth-child(2) > div > form > div > div:nth-child(2) > button > span.MuiButton-label");
}
get errorValidation() {
return $("#root > div > div:nth-child(2) > div > form > div > div:nth-child(3) > div > div.MuiAlert-message");
}
get accountBalance() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span");
}
get accountBalanceText() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div > div > div.MuiAlert-message");
}
get walletAddress() {
return $("#root > div > div:nth-child(1) > div:nth-child(3) > div:nth-child(2) > div > div.MuiCardContent-root > div > p");
}
get createNewAccount(){
return $("#root > div > div:nth-child(2) > div > form > div > div:nth-child(3) > a");
}
//login to the application
enterMnemonic = async(mnemonic) => {
await this.mnemonic.addValue(mnemonic);
await this.signInButton.click();
await this.accountBalance.isExisting();
}
}
module.exports = new WalletLogin()
@@ -0,0 +1,40 @@
class WalletReceive {
//can these selectors be nicer like the id's?
get header() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span");
}
get walletAddress() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(1) > span");
}
get copyButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(1) > button > span.MuiButton-label");
}
get qrCode() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(2) > div > canvas");
}
get information() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiAlert-message");
}
WaitForButtonChangeOnCopy = async () => {
await this.copyButton.click();
await this.copyButton.waitForDisplayed({ timeout: 1500 });
await this.copyButton.waitUntil(async function () {
return (await this.getText()) === 'COPIED'
}, {
timeout: 1500,
timeoutMsg: 'expected text to be different after 1.5s'
});
}
}
module.exports = new WalletReceive()
@@ -0,0 +1,76 @@
class WalletSend {
get fromAddress(){
return $("#from");
}
get toAddress(){
return $("#to");
}
get amount(){
return $("#amount")
}
//can these selectors be nicer like the id's?
get nextButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(3) > button > span.MuiButton-label");
}
get sendHeader(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span");
}
get transferAmount(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(7) > p:nth-child(2)");
}
get accountBalance(){
return $("#root > div > div:nth-child(1) > div:nth-child(3) > div:nth-child(1) > div > div.MuiCardContent-root > div > div > h6");
}
get amountReviewAndSend(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(5) > p:nth-child(2)");
}
get toAddressReviewAndSend(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(3) > p:nth-child(2)");
}
get fromAddressReviewAndSend(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(1) > p:nth-child(2)");
}
get transferFeeAmount(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div > div:nth-child(7) > p:nth-child(2)");
}
get reviewAndSendBackButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(3) > button.MuiButtonBase-root.MuiButton-root.MuiButton-text.MuiButton-disableElevation > span.MuiButton-label");
}
get sendButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(3) > button.MuiButtonBase-root.MuiButton-root.MuiButton-contained.MuiButton-containedPrimary.MuiButton-disableElevation > span.MuiButton-label");
}
get transactionComplete(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div:nth-child(1) > p");
}
get transactionCompleteRecipient(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div.MuiPaper-root.MuiCard-root.MuiPaper-outlined.MuiPaper-rounded > div:nth-child(1) > div:nth-child(2) > p");
}
get transactionCompleteAmount(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > div > div.MuiPaper-root.MuiCard-root.MuiPaper-outlined.MuiPaper-rounded > div:nth-child(2) > div:nth-child(2) > p");
}
get finishButton(){
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(3) > button");
}
}
module.exports = new WalletSend()
@@ -0,0 +1,23 @@
class WallentUndelegate {
//todo
get transactionFee() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(2) > div > div.MuiAlert-message");
}
get mixNodeRadioButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(1) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-20.MuiRadio-root.MuiRadio-colorSecondary.PrivateSwitchBase-checked-21.Mui-checked.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get gatewayRadionButton() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(1) > div > div.MuiGrid-root.MuiGrid-container.MuiGrid-item.MuiGrid-justify-content-xs-space-between.MuiGrid-grid-xs-12 > div:nth-child(1) > fieldset > div > label:nth-child(2) > span.MuiButtonBase-root.MuiIconButton-root.PrivateSwitchBase-root-20.MuiRadio-root.MuiRadio-colorSecondary.MuiIconButton-colorSecondary > span.MuiIconButton-label > input");
}
get nodeIdentity() {
return $("#mui-55011");
}
get stakeButtonConfirmation() {
return $("#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardContent-root > div > div:nth-child(2) > button > span.MuiButton-label");
}
}
module.exports = new WallentUndelegate()
@@ -0,0 +1,57 @@
const userData = require('../../../common/data/user-data');
const helper = require('../../../common/helpers/helper');
const walletLogin = require('../../pages/wallet.login');
const textConstants = require('../../../common/constants/text-constants');
const walletHomepage = require('../../pages/wallet.homepage');
const bondPage = require('../../pages/wallet.bond');
describe("bonding and unbonding nodes", () => {
it("should have a node already bonded and validate no input fields are enabled", async () => {
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
await helper.navigateAndClick(walletHomepage.bondButton);
await helper.scrollIntoView(bondPage.selectAdvancedOptions);
await bondPage.selectAdvancedOptions.click();
//as bond node is mixed expect all the fields to be disabled
const getText = await bondPage.header.getText();
const getIdentity = await bondPage.identityKey.isEnabled();
const getSphinxKey = await bondPage.sphinxKey.isEnabled();
const amountToBond = await bondPage.amountToBond.isEnabled();
const hostInput = await bondPage.hostInput.isEnabled();
const bondButton = await bondPage.bondButton.isEnabled();
const verlocPort = await bondPage.verlocPort.isEnabled();
const httpApiPort = await bondPage.httpApiPort.isEnabled();
const mixPort = await bondPage.mixPort.isEnabled();
//assert all field are not functional
expect(getText).toEqual(textConstants.bondNodeHeaderText);
expect(getIdentity).toEqual(false);
expect(getSphinxKey).toEqual(false);
expect(amountToBond).toEqual(false);
expect(hostInput).toEqual(false);
expect(bondButton).toEqual(false);
expect(verlocPort).toEqual(false);
expect(httpApiPort).toEqual(false);
expect(mixPort).toEqual(false);
})
it("unbond mix monde screen should be present with the option to unbond", async () => {
//we do not want to unbond our node, check that elements are selectable
await helper.navigateAndClick(walletHomepage.unBondButton);
const getText = await bondPage.header.getText();
const unbondButton = await bondPage.unBondButton.isEnabled();
const unbondText = await bondPage.unBondInformation.getText();
//assert all field are not functional
expect(getText).toEqual(textConstants.unbondNodeHeaderText);
expect(unbondButton).toEqual(true);
expect(unbondText).toEqual(textConstants.unbondMixNodeText);
})
});
@@ -0,0 +1,86 @@
const userData = require('../../../common/data/user-data');
const helper = require('../../../common/helpers/helper');
const walletLogin = require('../../pages/wallet.login');
const textConstants = require('../../../common/constants/text-constants');
const walletHomepage = require('../../pages/wallet.homepage');
const delegatePage = require('../../pages/wallet.delegate');
describe("delegate to a mix node or gateway", () => {
it("ensure that fields are enabled for existing user", async () => {
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
await helper.navigateAndClick(walletHomepage.delegateButton);
const getText = await delegatePage.header.getText();
expect(getText).toEqual(textConstants.delegateHeaderText);
})
it("submitting the form without input prompts validation errors", async () => {
await delegatePage.delegateStakeButton.click();
const getIdentityValidation = await delegatePage.identityValidation.getText();
const getAmountValidation = await delegatePage.amountToDelegateValidation.getText();
const getText = await delegatePage.header.getText();
expect(getText).toEqual(textConstants.delegateHeaderText);
expect(getIdentityValidation).toEqual(textConstants.nodeIdentityValidationText);
expect(getAmountValidation).toEqual(textConstants.amountValidationText);
})
it("input delegate amount and stake whilst checking account balances", async () => {
const balanceText = await delegatePage.accountBalance.getText();
const getTransfeeAmount = await delegatePage.transactionFeeAmount.getText();
await delegatePage.nodeIdentity.setValue(userData.identity_key_to_delegate);
await delegatePage.amountToDelegate.setValue(userData.delegate_amount);
//transfer fee + amount delegation
const sumCost = await helper.calculateFees(balanceText, getTransfeeAmount, userData.delegate_amount);
await delegatePage.delegateStakeButton.click();
await delegatePage.finishSuccessDelegation.waitForClickable({ timeout: 10000 });
const getConfirmationText = await delegatePage.successfullyDelegate.getText();
expect(getConfirmationText).toContain(textConstants.delegationComplete);
const availablePunk = await delegatePage.accountBalance.getText();
//expect new account balance - the fee calculation above
expect(await helper.currentBalance(availablePunk)).toEqual(sumCost);
})
//currently skipping, investigating gateway bonding
it.skip("input gateway amount and stake then check account balances", async () => {
const balanceText = await delegatePage.accountBalance.getText();
const getTransfeeAmount = await delegatePage.transactionFeeAmount.getText();
await delegatePage.gateWayRadioButton.click();
await delegatePage.nodeIdentity.setValue(userData.identity_key_to_delegate_gateway);
await delegatePage.amountToDelegate.setValue(userData.delegate_amount);
//transfer fee + amount delegation
const sumCost = await helper.calculateFees(balanceText, getTransfeeAmount, userData.delegate_amount);
await delegatePage.delegateStakeButton.click();
await delegatePage.finishSuccessDelegation.waitForClickable({ timeout: 10000 });
const getConfirmationText = await delegatePage.successfullyDelegate.getText();
expect(getConfirmationText).toContain(textConstants.delegationComplete);
const availablePunk = await delegatePage.accountBalance.getText();
//expect new account balance - the fee calculation above
expect(await helper.currentBalance(availablePunk)).toEqual(sumCost);
})
});
@@ -0,0 +1,48 @@
const userData = require('../../../common/data/user-data');
const helper = require('../../../common/helpers/helper');
const walletLogin = require('../../pages/wallet.login');
const homepPage = require('../../pages/wallet.homepage');
const textConstants = require('../../../common/constants/text-constants');
describe("Simple navigational and input tests on the wallet home page", () => {
it("should have the sign in header", async () => {
const signInText = await walletLogin.signInLabel.getText();
expect(signInText).toEqual(textConstants.homePageSignIn);
});
it("submitting the sign in button with no input throws a validation error", async () => {
await walletLogin.signInButton.click();
const errorResponseText = await walletLogin.errorValidation.getText();
expect(errorResponseText).toEqual(textConstants.homePageErrorMnemonic);
});
//currently the punk_address is not fully displayed on the wallet ui wallet
it("successfully input a bip39 mnemonic and log in", async () => {
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
const getWalletAddress = await walletLogin.walletAddress.getText();
expect(userData.punk_address).toContain(getWalletAddress);
});
//log out to homepage
it("successfully log out the application", async () => {
await helper.scrollIntoView(homepPage.logOutButton);
await homepPage.logOutButton.click();
const isNewAccountPresent = await walletLogin.createNewAccount.getText();
expect(isNewAccountPresent).toEqual(textConstants.createOne);
});
});
@@ -0,0 +1,31 @@
const userData = require('../../../common/data/user-data');
const textConstants = require('../../../common/constants/text-constants');
const helper = require('../../../common/helpers/helper');
const walletLogin = require('../../pages/wallet.login');
const receive = require('../../pages/wallet.receive');
const walletHomepage = require('../../pages/wallet.homepage');
describe("provide the relevant information about a user nym wallet address", () => {
it("should have the receivers address and a qr code present", async () => {
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
await walletHomepage.receiveButton.click();
await receive.header.waitForDisplayed({ timeout: 1500 });
await receive.WaitForButtonChangeOnCopy();
//implement qr code scanner here
const textHeader = await receive.header.getText();
const getInformationText = await receive.information.getText();
const getPunkAddress = await receive.walletAddress.getText();
expect(getPunkAddress).toEqual(userData.punk_address);
expect(getInformationText).toEqual(textConstants.recievePageInformation);
expect(textConstants.receivePageHeaderText).toEqual(textHeader);
});
});
@@ -0,0 +1,45 @@
const userData = require('../../../common/data/user-data');
const helper = require('../../../common/helpers/helper');
const textConstants = require('../../../common/constants/text-constants');
const walletLogin = require('../../pages/wallet.login');
const sendWallet = require('../../pages/wallet.send');
const walletHomepage = require('../../pages/wallet.homepage');
describe("send punk to another a wallet", () => {
it("expect send screen to display the data", async () => {
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
await walletHomepage.sendButton.click();
const textHeader = await sendWallet.sendHeader.getText();
expect(textHeader).toContain(textConstants.sendPunk);
});
//continue sequential flow for test
//be wary about production - be wary of funds allocation factor in gas fees
it("send funds correctly to another punk address", async () => {
//already logged in due to the previous test
await sendWallet.toAddress.addValue(userData.receiver_address);
await sendWallet.amount.addValue(userData.amount_to_send);
await sendWallet.nextButton.waitForEnabled({ timeout: 3000 });
await sendWallet.nextButton.click();
await sendWallet.sendButton.click();
await sendWallet.finishButton.waitForClickable({ timeout: 10000 });
await sendWallet.finishButton.click();
//todo implement asserts around account balance at the start vs the end
});
});
@@ -0,0 +1,34 @@
const userData = require('../../../common/data/user-data');
const helper = require('../../../common/helpers/helper');
const walletLogin = require('../../pages/wallet.login');
const walletHomepage = require('../../pages/wallet.homepage');
const unDelegatePage = require('../../pages/wallet.delegate');
describe("un-delegate to a mix node or gateway", () => {
it("ensure that fields are enabled for existing user", async () => {
//we are ensuring that the fields are selectable for undelegation
//not proceeding to undelegate a node or gateway
const mnemonic = await helper.decodeBase(userData.mnemonic);
await walletLogin.enterMnemonic(mnemonic);
await helper.scrollIntoView(walletHomepage.unDelegateButton);
await helper.navigateAndClick(walletHomepage.unDelegateButton);
await unDelegatePage.unDelegateButton.waitForClickable({ timeout: 3000});
const button = await unDelegatePage.unDelegateButton.isEnabled();
expect(button).toEqual(true);
await unDelegatePage.unDelegateGatewayRadioButton.click();
const gateWaySelected = await unDelegatePage.unDelegateGatewayRadioButton.isSelected();
expect(gateWaySelected).toEqual(true);
const mixNodeRadioButton = await unDelegatePage.unMixNodeRadioButton.isSelected();
expect(mixNodeRadioButton).toEqual(false);
})
});
@@ -0,0 +1,12 @@
const walletLogin = require('../../pages/wallet.login');
const textConstants = require('../../../common/constants/text-constants');
describe("non existing wallet holder", () => {
it("create new account", async () => {
const signInText = await walletLogin.signInLabel.getText();
expect(signInText).toEqual(textConstants.homePageSignIn);
await walletLogin.createNewAccount.click();
})
});
+65
View File
@@ -0,0 +1,65 @@
const os = require("os");
const path = require("path");
const { spawn, spawnSync } = require("child_process");
const nym_path = "../target/release/tauri-wallet";
exports.config = {
//run sequentially, as using one default user may cause issues for parallel test runs for now
specs: [
"./tests/specs/existinguser/test.wallet.home.js",
"./tests/specs/existinguser/test.wallet.send.js",
"./tests/specs/existinguser/test.wallet.receive.js",
"./tests/specs/existinguser/test.wallet.bond.js",
"./tests/specs/existinguser/test.wallet.delegate.js",
"./tests/specs/newuser/test.wallet.create.js"
],
//run tests by providing --suite {{login}}
suites: {
login: ["./tests/specs/existinguser/test.wallet.home.js"],
sendAndReceive: ["./tests/specs/existinguser/test.wallet.send.js",
"./tests/specs/existinguser/test.wallet.receive.js"],
bond: ["./tests/specs/existinguser/test.wallet.bond.js"],
delegate: ["./tests/specs/existinguser/test.wallet.delegate.js",
"./tests/specs/existinguser/test.wallet.undelegate.js"],
nonExsistingUser : ["./tests/specs/newuser/test.wallet.create.js"]
},
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
"tauri:options": {
application: nym_path,
},
},
],
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: 'info',
bail: 0,
framework: 'mocha',
reporters: ['spec'],
mochaOpts: {
ui: 'bdd',
timeout: 60000
},
logLevel: 'debug',
// this is documentented in the readme - you will need to build the project first
// ensure the rust project is built since we expect this binary to exist for the webdriver sessions
//onPrepare: () => spawnSync("cargo", ["build", "--release"]),
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
beforeSession: () =>
(tauriDriver = spawn(
path.resolve(os.homedir(), ".cargo", "bin", "tauri-driver"),
[],
{ stdio: [null, process.stdout, process.stderr] }
)),
// clean up the `tauri-driver` process we spawned at the start of the session
afterSession: () => tauriDriver.kill()
}