Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 07b566071b | |||
| 5f231e3eac | |||
| 9d3cad2771 | |||
| ae0f9b1b7b | |||
| 8a1e225365 | |||
| 2a6d0f3113 | |||
| d81e1fe44d | |||
| ef62ec6560 | |||
| 6649f859e6 | |||
| 617113555b | |||
| b9e8ba3215 | |||
| 2693ccafd1 | |||
| 8d78d23060 | |||
| 9543247def | |||
| 618c54ede3 | |||
| c91b63a6f8 | |||
| 4e63f2ce60 | |||
| bc80511863 | |||
| bc08b26ed4 | |||
| 81c5cafc60 | |||
| a9f25c2492 | |||
| 0ab5320656 | |||
| 28e7ce11e3 | |||
| 03364b848b | |||
| 8926d622b3 | |||
| a58d3dc6b2 | |||
| ece189773d | |||
| de2c3851ee | |||
| 6869de5640 |
@@ -1,105 +0,0 @@
|
|||||||
name: Build and upload binaries to CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'clients/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'contracts/**'
|
|
||||||
- 'explorer-api/**'
|
|
||||||
- 'gateway/**'
|
|
||||||
- 'integrations/**'
|
|
||||||
- 'mixnode/**'
|
|
||||||
- 'sdk/rust/nym-sdk/**'
|
|
||||||
- 'service-providers/**'
|
|
||||||
- 'nym-api/**'
|
|
||||||
- 'nym-outfox/**'
|
|
||||||
- 'tools/nym-cli/**'
|
|
||||||
- 'tools/ts-rs-cli/**'
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'clients/**'
|
|
||||||
- 'common/**'
|
|
||||||
- 'contracts/**'
|
|
||||||
- 'explorer-api/**'
|
|
||||||
- 'gateway/**'
|
|
||||||
- 'integrations/**'
|
|
||||||
- 'mixnode/**'
|
|
||||||
- 'sdk/rust/nym-sdk/**'
|
|
||||||
- 'service-providers/**'
|
|
||||||
- 'nym-api/**'
|
|
||||||
- 'nym-outfox/**'
|
|
||||||
- 'tools/nym-cli/**'
|
|
||||||
- 'tools/ts-rs-cli/**'
|
|
||||||
|
|
||||||
env:
|
|
||||||
NETWORK: mainnet
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish-nym:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
platform: [ubuntu-20.04]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Install Dependencies (Linux)
|
|
||||||
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Build all binaries
|
|
||||||
uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: build
|
|
||||||
args: --workspace --release
|
|
||||||
|
|
||||||
- name: Install Rust stable
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
target: wasm32-unknown-unknown
|
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
- name: Build release contracts
|
|
||||||
run: make wasm
|
|
||||||
|
|
||||||
- name: Prepare build output
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
rm -rf ci-builds || true
|
|
||||||
mkdir ci-builds
|
|
||||||
|
|
||||||
cp target/release/nym-client ci-builds
|
|
||||||
cp target/release/nym-gateway ci-builds
|
|
||||||
cp target/release/nym-mixnode ci-builds
|
|
||||||
cp target/release/nym-socks5-client ci-builds
|
|
||||||
cp target/release/nym-api ci-builds
|
|
||||||
cp target/release/nym-network-requester ci-builds
|
|
||||||
cp target/release/nym-network-statistics ci-builds
|
|
||||||
cp target/release/nym-cli ci-builds
|
|
||||||
|
|
||||||
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm ci-builds
|
|
||||||
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm ci-builds
|
|
||||||
|
|
||||||
- name: Deploy branch to CI www
|
|
||||||
continue-on-error: true
|
|
||||||
uses: easingthemes/ssh-deploy@main
|
|
||||||
env:
|
|
||||||
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
|
||||||
ARGS: "-rltgoDzvO --delete"
|
|
||||||
SOURCE: "ci-builds/"
|
|
||||||
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
|
||||||
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
|
||||||
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/${{ env.GITHUB_REF_NAME }}/
|
|
||||||
EXCLUDE: "/dist/, /node_modules/"
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
name: Tests for validator API
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- "nym-api/tests/**"
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: nym-api/tests
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: validator api tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Node v18
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18.1.0
|
|
||||||
|
|
||||||
- name: Install yarn
|
|
||||||
run: yarn install
|
|
||||||
|
|
||||||
- name: Run yarn
|
|
||||||
run: yarn
|
|
||||||
|
|
||||||
- name: Launch tests
|
|
||||||
run: yarn test:qa
|
|
||||||
working-directory: nym-api/tests
|
|
||||||
@@ -59,7 +59,7 @@ pub(crate) mod tests {
|
|||||||
use coconut_dkg_common::dealer::DealerDetails;
|
use coconut_dkg_common::dealer::DealerDetails;
|
||||||
use cosmwasm_std::Addr;
|
use cosmwasm_std::Addr;
|
||||||
use dkg::bte::keys::KeyPair as DkgKeyPair;
|
use dkg::bte::keys::KeyPair as DkgKeyPair;
|
||||||
use dkg::bte::{Params, PublicKeyWithProof};
|
use dkg::bte::Params;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -186,18 +186,8 @@ pub(crate) mod tests {
|
|||||||
let mut bytes = bs58::decode(details.bte_public_key_with_proof.clone())
|
let mut bytes = bs58::decode(details.bte_public_key_with_proof.clone())
|
||||||
.into_vec()
|
.into_vec()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// Find another value for last byte that still deserializes to a public key with proof
|
let last_byte = bytes.last_mut().unwrap();
|
||||||
let initial_byte = *bytes.last_mut().unwrap();
|
*last_byte += 1;
|
||||||
loop {
|
|
||||||
let last_byte = bytes.last_mut().unwrap();
|
|
||||||
let (ret, _) = last_byte.overflowing_add(1);
|
|
||||||
*last_byte = ret;
|
|
||||||
// stop when we find that value, or if we do a full round trip of u8 values
|
|
||||||
// and can't find one, in which case this test is invalid
|
|
||||||
if PublicKeyWithProof::try_from_bytes(&bytes).is_ok() || ret == initial_byte {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
details.bte_public_key_with_proof = bs58::encode(&bytes).into_string();
|
details.bte_public_key_with_proof = bs58::encode(&bytes).into_string();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
-783
File diff suppressed because one or more lines are too long
@@ -12,22 +12,12 @@ describe("Get circulating supply", (): void => {
|
|||||||
it("Get circulating supply amounts", async (): Promise<void> => {
|
it("Get circulating supply amounts", async (): Promise<void> => {
|
||||||
const response = await contract.getCirculatingSupply();
|
const response = await contract.getCirculatingSupply();
|
||||||
|
|
||||||
const initial: number = +response.total_supply.amount;
|
let initial: number = +response.initial_supply.amount;
|
||||||
const mixmining: number = +response.mixmining_reserve.amount;
|
let mixmining: number = +response.mixmining_reserve.amount;
|
||||||
const vest: number = +response.vesting_tokens.amount;
|
let vest: number = +response.vesting_tokens.amount;
|
||||||
const circsupply: number = +response.circulating_supply.amount;
|
let circsupply: number = +response.circulating_supply.amount;
|
||||||
|
|
||||||
expect(typeof response.vesting_tokens.amount).toBe("string");
|
expect(typeof response.vesting_tokens.amount).toBe("string");
|
||||||
expect(initial - mixmining - vest).toStrictEqual(circsupply);
|
expect(initial - mixmining - vest).toStrictEqual(circsupply);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
it("Get total supply value", async (): Promise<void> => {
|
|
||||||
const response = await contract.getTotalSupplyValue();
|
|
||||||
expect(typeof response).toBe("number");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Get circulating supply value", async (): Promise<void> => {
|
|
||||||
const response = await contract.getCirculatingSupplyValue();
|
|
||||||
expect(typeof response).toBe("number");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
+57
-127
@@ -17,12 +17,8 @@ describe("Get mixnode data", (): void => {
|
|||||||
//bond information overview
|
//bond information overview
|
||||||
expect(typeof mixnode.bond_information.mix_id).toBe("number");
|
expect(typeof mixnode.bond_information.mix_id).toBe("number");
|
||||||
expect(typeof mixnode.bond_information.owner).toBe("string");
|
expect(typeof mixnode.bond_information.owner).toBe("string");
|
||||||
expect(typeof mixnode.bond_information.original_pledge.amount).toBe(
|
expect(typeof mixnode.bond_information.original_pledge.amount).toBe("string");
|
||||||
"string"
|
expect(typeof mixnode.bond_information.original_pledge.denom).toBe("string");
|
||||||
);
|
|
||||||
expect(typeof mixnode.bond_information.original_pledge.denom).toBe(
|
|
||||||
"string"
|
|
||||||
);
|
|
||||||
expect(typeof mixnode.bond_information.layer).toBe("number");
|
expect(typeof mixnode.bond_information.layer).toBe("number");
|
||||||
expect(typeof mixnode.bond_information.bonding_height).toBe("number");
|
expect(typeof mixnode.bond_information.bonding_height).toBe("number");
|
||||||
expect(typeof mixnode.bond_information.is_unbonding).toBe("boolean");
|
expect(typeof mixnode.bond_information.is_unbonding).toBe("boolean");
|
||||||
@@ -35,12 +31,8 @@ describe("Get mixnode data", (): void => {
|
|||||||
|
|
||||||
//mixnode
|
//mixnode
|
||||||
expect(typeof mixnode.bond_information.mix_node.host).toBe("string");
|
expect(typeof mixnode.bond_information.mix_node.host).toBe("string");
|
||||||
expect(mixnode.bond_information.mix_node.http_api_port).toStrictEqual(
|
expect(mixnode.bond_information.mix_node.http_api_port).toStrictEqual(8000);
|
||||||
8000
|
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe("number");
|
||||||
);
|
|
||||||
expect(typeof mixnode.bond_information.mix_node.verloc_port).toBe(
|
|
||||||
"number"
|
|
||||||
);
|
|
||||||
expect(typeof mixnode.bond_information.mix_node.mix_port).toBe("number");
|
expect(typeof mixnode.bond_information.mix_node.mix_port).toBe("number");
|
||||||
expect(mixnode.bond_information.mix_node.mix_port).toStrictEqual(1789);
|
expect(mixnode.bond_information.mix_node.mix_port).toStrictEqual(1789);
|
||||||
expect(mixnode.bond_information.mix_node.verloc_port).toStrictEqual(1790);
|
expect(mixnode.bond_information.mix_node.verloc_port).toStrictEqual(1790);
|
||||||
@@ -48,39 +40,30 @@ describe("Get mixnode data", (): void => {
|
|||||||
const identitykey = mixnode.bond_information.mix_node.identity_key;
|
const identitykey = mixnode.bond_information.mix_node.identity_key;
|
||||||
if (typeof identitykey === "string") {
|
if (typeof identitykey === "string") {
|
||||||
if (identitykey.length === 43) {
|
if (identitykey.length === 43) {
|
||||||
return true;
|
return true
|
||||||
} else expect(identitykey).toHaveLength(44);
|
}
|
||||||
|
else expect(identitykey).toHaveLength(44);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sphinx = mixnode.bond_information.mix_node.sphinx_key;
|
const sphinx = mixnode.bond_information.mix_node.sphinx_key
|
||||||
if (typeof sphinx === "string") {
|
if (typeof sphinx === "string") {
|
||||||
if (sphinx.length === 43) {
|
if (sphinx.length === 43) {
|
||||||
return true;
|
return true
|
||||||
} else expect(sphinx).toHaveLength(44);
|
}
|
||||||
|
else expect(sphinx).toHaveLength(44);
|
||||||
}
|
}
|
||||||
|
|
||||||
//rewarding details
|
//rewarding details
|
||||||
expect(
|
expect(typeof mixnode.rewarding_details.cost_params.profit_margin_percent).toBe("string");
|
||||||
typeof mixnode.rewarding_details.cost_params.profit_margin_percent
|
expect(typeof mixnode.rewarding_details.cost_params.interval_operating_cost.denom).toBe("string");
|
||||||
).toBe("string");
|
expect(typeof mixnode.rewarding_details.cost_params.interval_operating_cost.amount).toBe("string");
|
||||||
expect(
|
|
||||||
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
|
|
||||||
.denom
|
|
||||||
).toBe("string");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.rewarding_details.cost_params.interval_operating_cost
|
|
||||||
.amount
|
|
||||||
).toBe("string");
|
|
||||||
expect(typeof mixnode.rewarding_details.operator).toBe("string");
|
expect(typeof mixnode.rewarding_details.operator).toBe("string");
|
||||||
expect(typeof mixnode.rewarding_details.delegates).toBe("string");
|
expect(typeof mixnode.rewarding_details.delegates).toBe("string");
|
||||||
expect(typeof mixnode.rewarding_details.total_unit_reward).toBe("string");
|
expect(typeof mixnode.rewarding_details.total_unit_reward).toBe("string");
|
||||||
expect(typeof mixnode.rewarding_details.unit_delegation).toBe("string");
|
expect(typeof mixnode.rewarding_details.unit_delegation).toBe("string");
|
||||||
expect(typeof mixnode.rewarding_details.last_rewarded_epoch).toBe(
|
expect(typeof mixnode.rewarding_details.last_rewarded_epoch).toBe("number");
|
||||||
"number"
|
expect(typeof mixnode.rewarding_details.unique_delegations).toBe("number");
|
||||||
);
|
|
||||||
expect(typeof mixnode.rewarding_details.unique_delegations).toBe(
|
|
||||||
"number"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,139 +79,85 @@ describe("Get mixnode data", (): void => {
|
|||||||
expect(typeof mixnode.family).toBe("string");
|
expect(typeof mixnode.family).toBe("string");
|
||||||
|
|
||||||
//mixnode details bond info
|
//mixnode details bond info
|
||||||
expect(typeof mixnode.mixnode_details.bond_information.mix_id).toBe(
|
expect(typeof mixnode.mixnode_details.bond_information.mix_id).toBe("number")
|
||||||
"number"
|
expect(typeof mixnode.mixnode_details.bond_information.owner).toBe("string");
|
||||||
);
|
expect(typeof mixnode.mixnode_details.bond_information.original_pledge.amount).toBe("string");
|
||||||
expect(typeof mixnode.mixnode_details.bond_information.owner).toBe(
|
expect(typeof mixnode.mixnode_details.bond_information.original_pledge.denom).toBe("string");
|
||||||
"string"
|
expect(typeof mixnode.mixnode_details.bond_information.layer).toBe("number");
|
||||||
);
|
expect(typeof mixnode.mixnode_details.bond_information.bonding_height).toBe("number");
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.bond_information.is_unbonding).toBe("boolean");
|
||||||
typeof mixnode.mixnode_details.bond_information.original_pledge.amount
|
|
||||||
).toBe("string");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.bond_information.original_pledge.denom
|
|
||||||
).toBe("string");
|
|
||||||
expect(typeof mixnode.mixnode_details.bond_information.layer).toBe(
|
|
||||||
"number"
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.bond_information.bonding_height
|
|
||||||
).toBe("number");
|
|
||||||
expect(typeof mixnode.mixnode_details.bond_information.is_unbonding).toBe(
|
|
||||||
"boolean"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mixnode.mixnode_details.bond_information.proxy === null) {
|
if (mixnode.mixnode_details.bond_information.proxy === null) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
expect(typeof mixnode.mixnode_details.bond_information.proxy).toBe(
|
else {
|
||||||
"string"
|
expect(typeof mixnode.mixnode_details.bond_information.proxy).toBe("string");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//mixnode
|
//mixnode
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.bond_information.mix_node.host).toBe("string")
|
||||||
typeof mixnode.mixnode_details.bond_information.mix_node.host
|
expect(mixnode.mixnode_details.bond_information.mix_node.http_api_port).toStrictEqual(8000);
|
||||||
).toBe("string");
|
expect(typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port).toBe("number")
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.bond_information.mix_node.mix_port).toBe("number")
|
||||||
mixnode.mixnode_details.bond_information.mix_node.http_api_port
|
expect(mixnode.mixnode_details.bond_information.mix_node.mix_port).toStrictEqual(1789);
|
||||||
).toStrictEqual(8000);
|
expect(mixnode.mixnode_details.bond_information.mix_node.verloc_port).toStrictEqual(1790)
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.bond_information.mix_node.verloc_port
|
|
||||||
).toBe("number");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.bond_information.mix_node.mix_port
|
|
||||||
).toBe("number");
|
|
||||||
expect(
|
|
||||||
mixnode.mixnode_details.bond_information.mix_node.mix_port
|
|
||||||
).toStrictEqual(1789);
|
|
||||||
expect(
|
|
||||||
mixnode.mixnode_details.bond_information.mix_node.verloc_port
|
|
||||||
).toStrictEqual(1790);
|
|
||||||
|
|
||||||
const identitykey2 =
|
let identitykey2 = mixnode.mixnode_details.bond_information.mix_node.identity_key
|
||||||
mixnode.mixnode_details.bond_information.mix_node.identity_key;
|
|
||||||
if (typeof identitykey2 === "string") {
|
if (typeof identitykey2 === "string") {
|
||||||
if (identitykey2.length === 43) {
|
if (identitykey2.length === 43) {
|
||||||
return true;
|
return true
|
||||||
} else expect(identitykey2).toHaveLength(44);
|
}
|
||||||
|
else expect(identitykey2).toHaveLength(44);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sphinx2 =
|
let sphinx2 = mixnode.mixnode_details.bond_information.mix_node.sphinx_key
|
||||||
mixnode.mixnode_details.bond_information.mix_node.sphinx_key;
|
|
||||||
if (typeof sphinx2 === "string") {
|
if (typeof sphinx2 === "string") {
|
||||||
if (sphinx2.length === 43) {
|
if (sphinx2.length === 43) {
|
||||||
return true;
|
return true
|
||||||
} else expect(sphinx2).toHaveLength(44);
|
}
|
||||||
|
else expect(sphinx2).toHaveLength(44);
|
||||||
}
|
}
|
||||||
|
|
||||||
//mixnode rewarding info
|
//mixnode rewarding info
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.profit_margin_percent).toBe("string")
|
||||||
typeof mixnode.mixnode_details.rewarding_details.cost_params
|
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.interval_operating_cost.denom).toBe("string")
|
||||||
.profit_margin_percent
|
expect(typeof mixnode.mixnode_details.rewarding_details.cost_params.interval_operating_cost.amount).toBe("string")
|
||||||
).toBe("string");
|
expect(typeof mixnode.mixnode_details.rewarding_details.operator).toBe("string")
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.rewarding_details.delegates).toBe("string")
|
||||||
typeof mixnode.mixnode_details.rewarding_details.cost_params
|
expect(typeof mixnode.mixnode_details.rewarding_details.total_unit_reward).toBe("string")
|
||||||
.interval_operating_cost.denom
|
expect(typeof mixnode.mixnode_details.rewarding_details.unit_delegation).toBe("string")
|
||||||
).toBe("string");
|
expect(typeof mixnode.mixnode_details.rewarding_details.last_rewarded_epoch).toBe("number")
|
||||||
expect(
|
expect(typeof mixnode.mixnode_details.rewarding_details.unique_delegations).toBe("number")
|
||||||
typeof mixnode.mixnode_details.rewarding_details.cost_params
|
|
||||||
.interval_operating_cost.amount
|
|
||||||
).toBe("string");
|
|
||||||
expect(typeof mixnode.mixnode_details.rewarding_details.operator).toBe(
|
|
||||||
"string"
|
|
||||||
);
|
|
||||||
expect(typeof mixnode.mixnode_details.rewarding_details.delegates).toBe(
|
|
||||||
"string"
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.rewarding_details.total_unit_reward
|
|
||||||
).toBe("string");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.rewarding_details.unit_delegation
|
|
||||||
).toBe("string");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
|
|
||||||
).toBe("number");
|
|
||||||
expect(
|
|
||||||
typeof mixnode.mixnode_details.rewarding_details.unique_delegations
|
|
||||||
).toBe("number");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get active mixnodes", async (): Promise<void> => {
|
it("Get active mixnodes", async (): Promise<void> => {
|
||||||
const response = await contract.getActiveMixnodes();
|
const response = await contract.getActiveMixnodes();
|
||||||
response.forEach(function (mixnode) {
|
response.forEach(function (mixnode) {
|
||||||
expect(
|
expect(mixnode.rewarding_details.cost_params.profit_margin_percent).toBeTruthy()
|
||||||
mixnode.rewarding_details.cost_params.profit_margin_percent
|
expect(typeof mixnode.bond_information.layer).toBe("number")
|
||||||
).toBeTruthy();
|
|
||||||
expect(typeof mixnode.bond_information.layer).toBe("number");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get active mixnodes detailed", async (): Promise<void> => {
|
it("Get active mixnodes detailed", async (): Promise<void> => {
|
||||||
const response = await contract.getActiveMixnodesDetailed();
|
const response = await contract.getActiveMixnodesDetailed();
|
||||||
response.forEach(function (mixnode) {
|
response.forEach(function (mixnode) {
|
||||||
expect(
|
expect(mixnode.mixnode_details.rewarding_details.cost_params.profit_margin_percent).toBeTruthy()
|
||||||
mixnode.mixnode_details.rewarding_details.cost_params
|
|
||||||
.profit_margin_percent
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get rewarded mixnodes", async (): Promise<void> => {
|
it("Get rewarded mixnodes", async (): Promise<void> => {
|
||||||
const response = await contract.getRewardedMixnodes();
|
const response = await contract.getRewardedMixnodes();
|
||||||
response.forEach(function (mixnode) {
|
response.forEach(function (mixnode) {
|
||||||
expect(mixnode.rewarding_details.last_rewarded_epoch).toBeTruthy();
|
expect(mixnode.rewarding_details.last_rewarded_epoch).toBeTruthy()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get rewarded mixnodes detailed", async (): Promise<void> => {
|
it("Get rewarded mixnodes detailed", async (): Promise<void> => {
|
||||||
const response = await contract.getRewardedMixnodesDetailed();
|
const response = await contract.getRewardedMixnodesDetailed();
|
||||||
response.forEach(function (mixnode) {
|
response.forEach(function (mixnode) {
|
||||||
expect(
|
expect(mixnode.mixnode_details.rewarding_details.last_rewarded_epoch).toBeTruthy()
|
||||||
mixnode.mixnode_details.rewarding_details.last_rewarded_epoch
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -238,4 +167,5 @@ describe("Get mixnode data", (): void => {
|
|||||||
expect(typeof value).toBe("number");
|
expect(typeof value).toBe("number");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,4 +46,5 @@ describe("Get gateway data", (): void => {
|
|||||||
expect(typeof response.last_hour).toBe("number");
|
expect(typeof response.last_hour).toBe("number");
|
||||||
expect(typeof response.last_day).toBe("number");
|
expect(typeof response.last_day).toBe("number");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ describe("Get mixnode data", (): void => {
|
|||||||
const response = await status.getMixnodeHistory(identity_key);
|
const response = await status.getMixnodeHistory(identity_key);
|
||||||
|
|
||||||
response.history.forEach((x) => {
|
response.history.forEach((x) => {
|
||||||
expect(typeof x.date).toBe("string");
|
console.log(x.date);
|
||||||
expect(typeof x.uptime).toBe("number");
|
console.log(x.uptime);
|
||||||
});
|
})
|
||||||
|
|
||||||
expect(identity_key).toStrictEqual(response.mix_id);
|
expect(identity_key).toStrictEqual(response.mix_id);
|
||||||
expect(typeof response.owner).toBe("string");
|
expect(typeof response.owner).toBe("string");
|
||||||
@@ -67,9 +67,7 @@ describe("Get mixnode data", (): void => {
|
|||||||
const identity_key = config.environmnetConfig.mix_id;
|
const identity_key = config.environmnetConfig.mix_id;
|
||||||
const response = await status.getMixnodeRewardComputation(identity_key);
|
const response = await status.getMixnodeRewardComputation(identity_key);
|
||||||
|
|
||||||
expect(response.reward_params.interval.sybil_resistance).toStrictEqual(
|
expect(response.reward_params.interval.sybil_resistance).toStrictEqual("0.3");
|
||||||
"0.3"
|
|
||||||
);
|
|
||||||
expect(response.reward_params.active_set_size).toStrictEqual(240);
|
expect(response.reward_params.active_set_size).toStrictEqual(240);
|
||||||
expect(typeof response.reward_params.interval.reward_pool).toBe("string");
|
expect(typeof response.reward_params.interval.reward_pool).toBe("string");
|
||||||
});
|
});
|
||||||
@@ -81,54 +79,42 @@ describe("Get mixnode data", (): void => {
|
|||||||
expect(typeof response.in_active).toBe("string");
|
expect(typeof response.in_active).toBe("string");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get all mixnodes inclusion probabilities", async (): Promise<void> => {
|
it("Get all mixnodes inclusion probability", async (): Promise<void> => {
|
||||||
const response = await status.getAllMixnodeInclusionProbability();
|
const response = await status.getAllMixnodeInclusionProbability();
|
||||||
const array = response.inclusion_probabilities;
|
|
||||||
array.forEach((x) => {
|
expect(response.inclusion_probabilities).toBeTruthy();
|
||||||
expect(typeof x.in_reserve).toBe("number");
|
|
||||||
expect(typeof x.mix_id).toBe("number");
|
|
||||||
});
|
|
||||||
expect(typeof response.elapsed.nanos).toBe("number");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get all mixnodes", async (): Promise<void> => {
|
it("Get all mixnodes", async (): Promise<void> => {
|
||||||
const response = await status.getDetailedMixnodes();
|
const response = await status.getDetailedMixnodes();
|
||||||
response.forEach((x) => {
|
|
||||||
expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
|
expect(typeof response.stake_saturation).toBe("string");
|
||||||
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
|
|
||||||
expect(typeof x.stake_saturation).toBe("string");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get all rewarded mixnodes", async (): Promise<void> => {
|
it("Get all rewarded mixnodes", async (): Promise<void> => {
|
||||||
const response = await status.getDetailedRewardedMixnodes();
|
const response = await status.getDetailedRewardedMixnodes();
|
||||||
response.forEach((x) => {
|
|
||||||
expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
|
expect(typeof response.mixnode_details.rewarding_details.last_rewarded_epoch).toBe("number");
|
||||||
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
|
|
||||||
expect(typeof x.stake_saturation).toBe("string");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Get all active mixnodes", async (): Promise<void> => {
|
it("Get all active mixnodes", async (): Promise<void> => {
|
||||||
const response = await status.getDetailedActiveMixnodes();
|
const response = await status.getDetailedActiveMixnodes();
|
||||||
response.forEach((x) => {
|
|
||||||
expect(typeof x.mixnode_details.bond_information.mix_id).toBe("number");
|
expect(typeof response.mixnode_details.bond_information.layer).toBe("number");
|
||||||
expect(typeof x.mixnode_details.bond_information.layer).toBe("number");
|
|
||||||
expect(typeof x.stake_saturation).toBe("string");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Compute mixnode reward estimation", (): void => {
|
describe("Compute mixnode reward estimation", (): void => {
|
||||||
beforeAll(async (): Promise<void> => {
|
beforeAll(async (): Promise<void> => {
|
||||||
status = new Status();
|
status = new Status();
|
||||||
config = ConfigHandler.getInstance();
|
config = ConfigHandler.getInstance();
|
||||||
});
|
});
|
||||||
// TODO Fix this test
|
it("with correct data", async (): Promise<void> => {
|
||||||
it.skip("with correct data", async (): Promise<void> => {
|
|
||||||
const response = await status.sendMixnodeRewardEstimatedComputation(8);
|
const response = await status.sendMixnodeRewardEstimatedComputation(8);
|
||||||
const body = expect(typeof response.estimation.total_node_reward).toBe(
|
const body =
|
||||||
"string"
|
|
||||||
);
|
expect(typeof response.estimation.total_node_reward).toBe("string");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,18 +12,4 @@ export default class ContractCache extends APIClient {
|
|||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getTotalSupplyValue(): Promise<number> {
|
|
||||||
const response = await this.restClient.sendGet({
|
|
||||||
route: `circulating-supply/total-supply-value`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getCirculatingSupplyValue(): Promise<number> {
|
|
||||||
const response = await this.restClient.sendGet({
|
|
||||||
route: `circulating-supply/circulating-supply-value`,
|
|
||||||
});
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import {
|
|||||||
AllGateways,
|
AllGateways,
|
||||||
AllMixnodes,
|
AllMixnodes,
|
||||||
EpochRewardParams,
|
EpochRewardParams,
|
||||||
BlacklistedGateways,
|
|
||||||
BlacklistedMixnodes,
|
|
||||||
CurrentEpoch,
|
CurrentEpoch,
|
||||||
} from "../types/ContractCacheTypes";
|
} from "../types/ContractCacheTypes";
|
||||||
import { APIClient } from "./abstracts/APIClient";
|
import { APIClient } from "./abstracts/APIClient";
|
||||||
@@ -64,14 +62,14 @@ export default class ContractCache extends APIClient {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getBlacklistedMixnodes(): Promise<BlacklistedMixnodes[]> {
|
public async getBlacklistedMixnodes(): Promise<[]> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `mixnodes/blacklisted`,
|
route: `mixnodes/blacklisted`,
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getBlacklistedGateways(): Promise<BlacklistedGateways[]> {
|
public async getBlacklistedGateways(): Promise<[]> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `gateways/blacklisted`,
|
route: `gateways/blacklisted`,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ export default class Status extends APIClient {
|
|||||||
|
|
||||||
public async getAllMixnodeInclusionProbability(): Promise<InclusionProbabilities> {
|
public async getAllMixnodeInclusionProbability(): Promise<InclusionProbabilities> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `/mixnodes/inclusion_probability`,
|
route: `/mixnodes/inclusion-probability`,
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDetailedMixnodes(): Promise<DetailedMixnodes[]> {
|
public async getDetailedMixnodes(): Promise<DetailedMixnodes> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `/mixnodes/detailed`,
|
route: `/mixnodes/detailed`,
|
||||||
});
|
});
|
||||||
@@ -161,7 +161,7 @@ export default class Status extends APIClient {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDetailedRewardedMixnodes(): Promise<DetailedMixnodes[]> {
|
public async getDetailedRewardedMixnodes(): Promise<DetailedMixnodes> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `/mixnodes/rewarded/detailed`,
|
route: `/mixnodes/rewarded/detailed`,
|
||||||
});
|
});
|
||||||
@@ -169,7 +169,7 @@ export default class Status extends APIClient {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDetailedActiveMixnodes(): Promise<DetailedMixnodes[]> {
|
public async getDetailedActiveMixnodes(): Promise<DetailedMixnodes> {
|
||||||
const response = await this.restClient.sendGet({
|
const response = await this.restClient.sendGet({
|
||||||
route: `/mixnodes/active/detailed`,
|
route: `/mixnodes/active/detailed`,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
export type Detailed = {
|
export type Detailed = {
|
||||||
total_supply: TotalSupply;
|
initial_supply: InitialSupply;
|
||||||
mixmining_reserve: MixminingReserve;
|
mixmining_reserve: MixminingReserve;
|
||||||
vesting_tokens: VestingTokens;
|
vesting_tokens: VestingTokens;
|
||||||
circulating_supply: CirculatingSupply;
|
circulating_supply: CirculatingSupply;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TotalSupply = {
|
export type InitialSupply = {
|
||||||
demon: "unym";
|
demon: "unym";
|
||||||
amount: string;
|
amount: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
export type AllMixnodes = {
|
export interface AllMixnodes {
|
||||||
bond_information: BondInformation;
|
bond_information: BondInformation;
|
||||||
rewarding_details: RewardingDetails;
|
rewarding_details: RewardingDetails;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type BondInformation = {
|
export interface BondInformation {
|
||||||
mix_id: number;
|
mix_id: number;
|
||||||
owner: string;
|
owner: string;
|
||||||
original_pledge: OriginalPledge;
|
original_pledge: OriginalPledge;
|
||||||
@@ -12,9 +12,9 @@ export type BondInformation = {
|
|||||||
proxy: string;
|
proxy: string;
|
||||||
bonding_height: number;
|
bonding_height: number;
|
||||||
is_unbonding: boolean;
|
is_unbonding: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RewardingDetails = {
|
export interface RewardingDetails {
|
||||||
cost_params: CostParams;
|
cost_params: CostParams;
|
||||||
operator: string;
|
operator: string;
|
||||||
delegates: string;
|
delegates: string;
|
||||||
@@ -22,29 +22,29 @@ export type RewardingDetails = {
|
|||||||
unit_delegation: string;
|
unit_delegation: string;
|
||||||
last_rewarded_epoch: number;
|
last_rewarded_epoch: number;
|
||||||
unique_delegations: number;
|
unique_delegations: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type CostParams = {
|
export interface CostParams {
|
||||||
profit_margin_percent: string;
|
profit_margin_percent: string;
|
||||||
interval_operating_cost: IntervalOperatingCost;
|
interval_operating_cost: IntervalOperatingCost;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type IntervalOperatingCost = {
|
export interface IntervalOperatingCost {
|
||||||
denom: string;
|
denom: string;
|
||||||
amount: string;
|
amount: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type OriginalPledge = {
|
export interface OriginalPledge {
|
||||||
denom: string;
|
denom: string;
|
||||||
amount: string;
|
amount: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type TotalDelegation = {
|
export interface TotalDelegation {
|
||||||
denom: string;
|
denom: string;
|
||||||
amount: string;
|
amount: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Mixnode = {
|
export interface Mixnode {
|
||||||
host: string;
|
host: string;
|
||||||
mix_port: number;
|
mix_port: number;
|
||||||
verloc_port: number;
|
verloc_port: number;
|
||||||
@@ -52,9 +52,9 @@ export type Mixnode = {
|
|||||||
sphinx_key: string;
|
sphinx_key: string;
|
||||||
identity_key: string;
|
identity_key: string;
|
||||||
version: string;
|
version: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type MixnodeBond = {
|
export interface MixnodeBond {
|
||||||
pledge_amount: OriginalPledge;
|
pledge_amount: OriginalPledge;
|
||||||
total_delegation: TotalDelegation;
|
total_delegation: TotalDelegation;
|
||||||
owner: string;
|
owner: string;
|
||||||
@@ -63,9 +63,9 @@ export type MixnodeBond = {
|
|||||||
mix_node: Mixnode;
|
mix_node: Mixnode;
|
||||||
proxy: string;
|
proxy: string;
|
||||||
accumulated_rewards: string;
|
accumulated_rewards: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type MixnodesDetailed = {
|
export interface MixnodesDetailed {
|
||||||
mixnode_details: AllMixnodes;
|
mixnode_details: AllMixnodes;
|
||||||
stake_saturation: string;
|
stake_saturation: string;
|
||||||
uncapped_stake_saturation: string;
|
uncapped_stake_saturation: string;
|
||||||
@@ -73,11 +73,7 @@ export type MixnodesDetailed = {
|
|||||||
estimated_operator_apy: string;
|
estimated_operator_apy: string;
|
||||||
estimated_delegators_apy: string;
|
estimated_delegators_apy: string;
|
||||||
family: string;
|
family: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type BlacklistedMixnodes = {};
|
|
||||||
|
|
||||||
export type BlacklistedGateways = {};
|
|
||||||
|
|
||||||
export interface Gateway {
|
export interface Gateway {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -97,13 +93,13 @@ export interface AllGateways {
|
|||||||
proxy: string;
|
proxy: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EpochRewardParams = {
|
export interface EpochRewardParams {
|
||||||
interval: Interval;
|
interval: Interval;
|
||||||
rewarded_set_size: number;
|
rewarded_set_size: number;
|
||||||
active_set_size: number;
|
active_set_size: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Interval = {
|
export interface Interval {
|
||||||
reward_pool: string;
|
reward_pool: string;
|
||||||
staking_supply: string;
|
staking_supply: string;
|
||||||
staking_supply_scale_factor: string;
|
staking_supply_scale_factor: string;
|
||||||
@@ -112,18 +108,18 @@ export type Interval = {
|
|||||||
sybil_resistance: string;
|
sybil_resistance: string;
|
||||||
active_set_work_factor: string;
|
active_set_work_factor: string;
|
||||||
interval_pool_emission: string;
|
interval_pool_emission: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type CurrentEpoch = {
|
export interface CurrentEpoch {
|
||||||
id: number;
|
id: number;
|
||||||
epochs_in_interval: number;
|
epochs_in_interval: number;
|
||||||
current_epoch_start: string;
|
current_epoch_start: string;
|
||||||
current_epoch_id: number;
|
current_epoch_id: number;
|
||||||
epoch_length: EpochLength;
|
epoch_length: EpochLength;
|
||||||
total_elapsed_epochs: number;
|
total_elapsed_epochs: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type EpochLength = {
|
export interface EpochLength {
|
||||||
secs: number;
|
secs: number;
|
||||||
nanos: number;
|
nanos: number;
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -20,6 +20,6 @@
|
|||||||
"typeRoots": ["node_modules/@types"],
|
"typeRoots": ["node_modules/@types"],
|
||||||
"alwaysStrict": true
|
"alwaysStrict": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "functional_test/*/*"],
|
"include": ["src/**/*", "tests/functional_test/*/*"],
|
||||||
"exclude": ["unit_test/**/*"]
|
"exclude": ["unit_test/**/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "nym-api-requests"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bs58 = "0.4.0"
|
|
||||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
|
||||||
cosmwasm-std = { version = "1.0.0", default-features = false }
|
|
||||||
getset = "0.1.1"
|
|
||||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
ts-rs = { version = "6.1.2", optional = true }
|
|
||||||
|
|
||||||
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
|
||||||
mixnet-contract-common = { path= "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
coconut = ["coconut-interface"]
|
|
||||||
generate-ts = ["ts-rs"]
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use cosmrs::AccountId;
|
|
||||||
use getset::{CopyGetters, Getters};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use coconut_interface::{
|
|
||||||
error::CoconutInterfaceError, Attribute, Base58, BlindSignRequest, Credential, VerificationKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
|
|
||||||
pub struct VerifyCredentialBody {
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
credential: Credential,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
proposal_id: u64,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
gateway_cosmos_addr: AccountId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerifyCredentialBody {
|
|
||||||
pub fn new(
|
|
||||||
credential: Credential,
|
|
||||||
proposal_id: u64,
|
|
||||||
gateway_cosmos_addr: AccountId,
|
|
||||||
) -> VerifyCredentialBody {
|
|
||||||
VerifyCredentialBody {
|
|
||||||
credential,
|
|
||||||
proposal_id,
|
|
||||||
gateway_cosmos_addr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct VerifyCredentialResponse {
|
|
||||||
pub verification_result: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerifyCredentialResponse {
|
|
||||||
pub fn new(verification_result: bool) -> Self {
|
|
||||||
VerifyCredentialResponse {
|
|
||||||
verification_result,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All strings are base58 encoded representations of structs
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
|
|
||||||
pub struct BlindSignRequestBody {
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
blind_sign_request: BlindSignRequest,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
tx_hash: String,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
signature: String,
|
|
||||||
public_attributes: Vec<String>,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
public_attributes_plain: Vec<String>,
|
|
||||||
#[getset(get = "pub")]
|
|
||||||
total_params: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlindSignRequestBody {
|
|
||||||
pub fn new(
|
|
||||||
blind_sign_request: &BlindSignRequest,
|
|
||||||
tx_hash: String,
|
|
||||||
signature: String,
|
|
||||||
public_attributes: &[Attribute],
|
|
||||||
public_attributes_plain: Vec<String>,
|
|
||||||
total_params: u32,
|
|
||||||
) -> BlindSignRequestBody {
|
|
||||||
BlindSignRequestBody {
|
|
||||||
blind_sign_request: blind_sign_request.clone(),
|
|
||||||
tx_hash,
|
|
||||||
signature,
|
|
||||||
public_attributes: public_attributes
|
|
||||||
.iter()
|
|
||||||
.map(|attr| attr.to_bs58())
|
|
||||||
.collect(),
|
|
||||||
public_attributes_plain,
|
|
||||||
total_params,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public_attributes(&self) -> Vec<Attribute> {
|
|
||||||
self.public_attributes
|
|
||||||
.iter()
|
|
||||||
.map(|x| Attribute::try_from_bs58(x).unwrap())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct BlindedSignatureResponse {
|
|
||||||
pub remote_key: [u8; 32],
|
|
||||||
pub encrypted_signature: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlindedSignatureResponse {
|
|
||||||
pub fn new(encrypted_signature: Vec<u8>, remote_key: [u8; 32]) -> BlindedSignatureResponse {
|
|
||||||
BlindedSignatureResponse {
|
|
||||||
encrypted_signature,
|
|
||||||
remote_key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_base58_string(&self) -> String {
|
|
||||||
bs58::encode(&self.to_bytes()).into_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, CoconutInterfaceError> {
|
|
||||||
let bytes = bs58::decode(val).into_vec()?;
|
|
||||||
Self::from_bytes(&bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
|
||||||
let mut bytes = self.remote_key.to_vec();
|
|
||||||
bytes.extend_from_slice(&self.encrypted_signature);
|
|
||||||
bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutInterfaceError> {
|
|
||||||
if bytes.len() < 32 {
|
|
||||||
return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32));
|
|
||||||
}
|
|
||||||
let mut remote_key = [0u8; 32];
|
|
||||||
remote_key.copy_from_slice(&bytes[..32]);
|
|
||||||
let encrypted_signature = bytes[32..].to_vec();
|
|
||||||
Ok(BlindedSignatureResponse {
|
|
||||||
remote_key,
|
|
||||||
encrypted_signature,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct VerificationKeyResponse {
|
|
||||||
pub key: VerificationKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerificationKeyResponse {
|
|
||||||
pub fn new(key: VerificationKey) -> VerificationKeyResponse {
|
|
||||||
VerificationKeyResponse { key }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct CosmosAddressResponse {
|
|
||||||
pub addr: AccountId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CosmosAddressResponse {
|
|
||||||
pub fn new(addr: AccountId) -> CosmosAddressResponse {
|
|
||||||
CosmosAddressResponse { addr }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[cfg(feature = "coconut")]
|
|
||||||
pub mod coconut;
|
|
||||||
pub mod models;
|
|
||||||
|
|
||||||
pub trait Deprecatable {
|
|
||||||
fn deprecate(self) -> Deprecated<Self>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deprecatable for T {}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub struct Deprecated<T> {
|
|
||||||
pub deprecated: bool,
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub response: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for Deprecated<T> {
|
|
||||||
fn from(response: T) -> Self {
|
|
||||||
Deprecated {
|
|
||||||
deprecated: true,
|
|
||||||
response,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use cosmwasm_std::{Coin, Decimal};
|
|
||||||
use mixnet_contract_common::families::FamilyHead;
|
|
||||||
use mixnet_contract_common::mixnode::MixNodeDetails;
|
|
||||||
use mixnet_contract_common::reward_params::{Performance, RewardingParams};
|
|
||||||
use mixnet_contract_common::rewarding::RewardEstimate;
|
|
||||||
use mixnet_contract_common::{
|
|
||||||
IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus,
|
|
||||||
};
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{fmt, time::Duration};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
|
||||||
pub struct RequestError {
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequestError {
|
|
||||||
pub fn new<S: Into<String>>(msg: S) -> Self {
|
|
||||||
RequestError {
|
|
||||||
message: msg.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message(&self) -> &str {
|
|
||||||
&self.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/MixnodeStatus.ts")
|
|
||||||
)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum MixnodeStatus {
|
|
||||||
Active, // in both the active set and the rewarded set
|
|
||||||
Standby, // only in the rewarded set
|
|
||||||
Inactive, // in neither the rewarded set nor the active set, but is bonded
|
|
||||||
NotFound, // doesn't even exist in the bonded set
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MixnodeStatus> for Option<RewardedSetNodeStatus> {
|
|
||||||
fn from(status: MixnodeStatus) -> Self {
|
|
||||||
match status {
|
|
||||||
MixnodeStatus::Active => Some(RewardedSetNodeStatus::Active),
|
|
||||||
MixnodeStatus::Standby => Some(RewardedSetNodeStatus::Standby),
|
|
||||||
MixnodeStatus::Inactive => None,
|
|
||||||
MixnodeStatus::NotFound => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MixnodeStatus {
|
|
||||||
pub fn is_active(&self) -> bool {
|
|
||||||
*self == MixnodeStatus::Active
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/MixnodeCoreStatusResponse.ts")
|
|
||||||
)]
|
|
||||||
pub struct MixnodeCoreStatusResponse {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
pub count: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/GatewayCoreStatusResponse.ts")
|
|
||||||
)]
|
|
||||||
pub struct GatewayCoreStatusResponse {
|
|
||||||
pub identity: String,
|
|
||||||
pub count: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/MixnodeStatusResponse.ts")
|
|
||||||
)]
|
|
||||||
pub struct MixnodeStatusResponse {
|
|
||||||
pub status: MixnodeStatus,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub struct MixNodeBondAnnotated {
|
|
||||||
pub mixnode_details: MixNodeDetails,
|
|
||||||
pub stake_saturation: StakeSaturation,
|
|
||||||
pub uncapped_stake_saturation: StakeSaturation,
|
|
||||||
pub performance: Performance,
|
|
||||||
pub estimated_operator_apy: Decimal,
|
|
||||||
pub estimated_delegators_apy: Decimal,
|
|
||||||
pub family: Option<FamilyHead>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MixNodeBondAnnotated {
|
|
||||||
pub fn mix_node(&self) -> &MixNode {
|
|
||||||
&self.mixnode_details.bond_information.mix_node
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mix_id(&self) -> MixId {
|
|
||||||
self.mixnode_details.mix_id()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub struct ComputeRewardEstParam {
|
|
||||||
pub performance: Option<Performance>,
|
|
||||||
pub active_in_rewarded_set: Option<bool>,
|
|
||||||
pub pledge_amount: Option<u64>,
|
|
||||||
pub total_delegation: Option<u64>,
|
|
||||||
pub interval_operating_cost: Option<Coin>,
|
|
||||||
pub profit_margin_percent: Option<Percent>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/RewardEstimationResponse.ts")
|
|
||||||
)]
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub struct RewardEstimationResponse {
|
|
||||||
pub estimation: RewardEstimate,
|
|
||||||
pub reward_params: RewardingParams,
|
|
||||||
pub epoch: Interval,
|
|
||||||
#[cfg_attr(feature = "generate-ts", ts(type = "number"))]
|
|
||||||
pub as_at: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub struct UptimeResponse {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
pub avg_uptime: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/StakeSaturationResponse.ts")
|
|
||||||
)]
|
|
||||||
pub struct StakeSaturationResponse {
|
|
||||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
|
||||||
pub saturation: StakeSaturation,
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
|
||||||
pub uncapped_saturation: StakeSaturation,
|
|
||||||
pub as_at: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type StakeSaturation = Decimal;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/SelectionChance.ts")
|
|
||||||
)]
|
|
||||||
pub enum SelectionChance {
|
|
||||||
High,
|
|
||||||
Good,
|
|
||||||
Low,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<f64> for SelectionChance {
|
|
||||||
fn from(p: f64) -> SelectionChance {
|
|
||||||
match p {
|
|
||||||
p if p >= 0.7 => SelectionChance::High,
|
|
||||||
p if p >= 0.3 => SelectionChance::Good,
|
|
||||||
_ => SelectionChance::Low,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Decimal> for SelectionChance {
|
|
||||||
fn from(p: Decimal) -> Self {
|
|
||||||
match p {
|
|
||||||
p if p >= Decimal::from_ratio(70u32, 100u32) => SelectionChance::High,
|
|
||||||
p if p >= Decimal::from_ratio(30u32, 100u32) => SelectionChance::Good,
|
|
||||||
_ => SelectionChance::Low,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SelectionChance {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
SelectionChance::High => write!(f, "High"),
|
|
||||||
SelectionChance::Good => write!(f, "Good"),
|
|
||||||
SelectionChance::Low => write!(f, "Low"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/InclusionProbabilityResponse.ts")
|
|
||||||
)]
|
|
||||||
pub struct InclusionProbabilityResponse {
|
|
||||||
pub in_active: SelectionChance,
|
|
||||||
pub in_reserve: SelectionChance,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for InclusionProbabilityResponse {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"in_active: {}, in_reserve: {}",
|
|
||||||
self.in_active, self.in_reserve
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, schemars::JsonSchema)]
|
|
||||||
pub struct AllInclusionProbabilitiesResponse {
|
|
||||||
pub inclusion_probabilities: Vec<InclusionProbability>,
|
|
||||||
pub samples: u64,
|
|
||||||
pub elapsed: Duration,
|
|
||||||
pub delta_max: f64,
|
|
||||||
pub delta_l2: f64,
|
|
||||||
pub as_at: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, schemars::JsonSchema)]
|
|
||||||
pub struct InclusionProbability {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
pub in_active: f64,
|
|
||||||
pub in_reserve: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Uptime = u8;
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
|
|
||||||
pub struct MixnodeStatusReportResponse {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
pub identity: IdentityKey,
|
|
||||||
pub owner: String,
|
|
||||||
pub most_recent: Uptime,
|
|
||||||
pub last_hour: Uptime,
|
|
||||||
pub last_day: Uptime,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
|
|
||||||
pub struct GatewayStatusReportResponse {
|
|
||||||
pub identity: String,
|
|
||||||
pub owner: String,
|
|
||||||
pub most_recent: Uptime,
|
|
||||||
pub last_hour: Uptime,
|
|
||||||
pub last_day: Uptime,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
|
|
||||||
pub struct HistoricalUptimeResponse {
|
|
||||||
pub date: String,
|
|
||||||
pub uptime: Uptime,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
|
|
||||||
pub struct MixnodeUptimeHistoryResponse {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
pub identity: String,
|
|
||||||
pub owner: String,
|
|
||||||
pub history: Vec<HistoricalUptimeResponse>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, schemars::JsonSchema)]
|
|
||||||
pub struct GatewayUptimeHistoryResponse {
|
|
||||||
pub identity: String,
|
|
||||||
pub owner: String,
|
|
||||||
pub history: Vec<HistoricalUptimeResponse>,
|
|
||||||
}
|
|
||||||
Vendored
BIN
Binary file not shown.
@@ -40,7 +40,7 @@ export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string }>
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<AddressTooltip address={address} visible={!showEntireAddress}>
|
<AddressTooltip address={address} visible={!showEntireAddress}>
|
||||||
<Typography data-testid="wallet-address" variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
|
<Typography variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
|
||||||
{showEntireAddress ? address || '' : splice(6, address)}
|
{showEntireAddress ? address || '' : splice(6, address)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</AddressTooltip>
|
</AddressTooltip>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React from 'react';
|
|||||||
import { Button, Stack, TextField, Typography } from '@mui/material';
|
import { Button, Stack, TextField, Typography } from '@mui/material';
|
||||||
import { Check, ContentCopySharp } from '@mui/icons-material';
|
import { Check, ContentCopySharp } from '@mui/icons-material';
|
||||||
import { Warning } from './Warning';
|
import { Warning } from './Warning';
|
||||||
import { MnemonicModal } from './Accounts/modals/MnemonicModal';
|
|
||||||
|
|
||||||
export const Mnemonic = ({
|
export const Mnemonic = ({
|
||||||
mnemonic,
|
mnemonic,
|
||||||
@@ -15,19 +14,18 @@ export const Mnemonic = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<Stack spacing={2} alignItems="center">
|
<Stack spacing={2} alignItems="center">
|
||||||
<Warning>
|
<Warning>
|
||||||
<Typography sx={{ textAlign: 'center' }} data-testid="below24word">
|
<Typography sx={{ textAlign: 'center' }}>
|
||||||
Below is your 24 word mnemonic, make sure to store it in a safe place for accessing your wallet in the future
|
Below is your 24 word mnemonic, make sure to store it in a safe place for accessing your wallet in the future
|
||||||
</Typography>
|
</Typography>
|
||||||
</Warning>
|
</Warning>
|
||||||
<TextField
|
<TextField
|
||||||
label="Mnemonic"
|
label="Mnemonic"
|
||||||
id="mnemonicPhrase"
|
|
||||||
type="input"
|
type="input"
|
||||||
value={mnemonic}
|
value={mnemonic}
|
||||||
multiline
|
multiline
|
||||||
autoFocus={false}
|
autoFocus={false}
|
||||||
fullWidth
|
fullWidth
|
||||||
inputProps={{
|
inputProps={{
|
||||||
style: {
|
style: {
|
||||||
height: '160px',
|
height: '160px',
|
||||||
},
|
},
|
||||||
@@ -41,7 +39,6 @@ export const Mnemonic = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
data-testid="copyMnemonic"
|
|
||||||
color="inherit"
|
color="inherit"
|
||||||
disableElevation
|
disableElevation
|
||||||
size="large"
|
size="large"
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ export const Nav = () => {
|
|||||||
<ListItem
|
<ListItem
|
||||||
disableGutters
|
disableGutters
|
||||||
key={label}
|
key={label}
|
||||||
data-testid={label}
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
sx={{
|
sx={{
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const NetworkItem: FCWithChildren<{ title: string; isSelected: boolean; onSelect
|
|||||||
isSelected,
|
isSelected,
|
||||||
onSelect,
|
onSelect,
|
||||||
}) => (
|
}) => (
|
||||||
<ListItem button onClick={onSelect} data-testid={title}>
|
<ListItem button onClick={onSelect}>
|
||||||
<ListItemIcon>{isSelected && <CheckSharp color="success" />}</ListItemIcon>
|
<ListItemIcon>{isSelected && <CheckSharp color="success" />}</ListItemIcon>
|
||||||
<ListItemText>{title}</ListItemText>
|
<ListItemText>{title}</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
@@ -38,7 +38,6 @@ export const NetworkSelector = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
data-testid="networkEnv"
|
|
||||||
variant="text"
|
variant="text"
|
||||||
color="inherit"
|
color="inherit"
|
||||||
sx={{ color: 'text.primary', fontSize: 14 }}
|
sx={{ color: 'text.primary', fontSize: 14 }}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ export const MnemonicInput: FCWithChildren<{
|
|||||||
autoFocus
|
autoFocus
|
||||||
fullWidth
|
fullWidth
|
||||||
multiline={showMnemonic}
|
multiline={showMnemonic}
|
||||||
inputProps={{
|
|
||||||
"data-testid": "inputMnemonic" }}
|
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
sx={{
|
sx={{
|
||||||
'input::-webkit-textfield-decoration-container': {
|
'input::-webkit-textfield-decoration-container': {
|
||||||
@@ -31,7 +29,6 @@ export const MnemonicInput: FCWithChildren<{
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
data-testid="Reveal Mnemonic"
|
|
||||||
control={<Checkbox checked={Boolean(showMnemonic)} onChange={() => setShowMnemonic((show) => !show)} />}
|
control={<Checkbox checked={Boolean(showMnemonic)} onChange={() => setShowMnemonic((show) => !show)} />}
|
||||||
label="Reveal my mnemonic"
|
label="Reveal my mnemonic"
|
||||||
/>
|
/>
|
||||||
@@ -71,9 +68,6 @@ export const PasswordInput: FCWithChildren<{
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
inputProps={{
|
|
||||||
"data-testid": label,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{error && <Error message={error} />}
|
{error && <Error message={error} />}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import React from 'react';
|
|||||||
import { Typography } from '@mui/material';
|
import { Typography } from '@mui/material';
|
||||||
|
|
||||||
export const Title = ({ title }: { title: string }) => (
|
export const Title = ({ title }: { title: string }) => (
|
||||||
<Typography data-testid={title} sx={{ color: 'common.white', fontWeight: 600, fontSize: 20 }}>{title}</Typography>
|
<Typography sx={{ color: 'common.white', fontWeight: 600, fontSize: 20 }}>{title}</Typography>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Subtitle = ({ subtitle }: { subtitle: string }) => (
|
export const Subtitle = ({ subtitle }: { subtitle: string }) => (
|
||||||
<Typography data-testid={subtitle} sx={{ color: 'common.white', textAlign: 'center', maxWidth: 450 }}>{subtitle}</Typography>
|
<Typography sx={{ color: 'common.white', textAlign: 'center', maxWidth: 450 }}>{subtitle}</Typography>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SubtitleSlick = ({ subtitle }: { subtitle: string }) => (
|
export const SubtitleSlick = ({ subtitle }: { subtitle: string }) => (
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const WordTiles = ({
|
|||||||
return (
|
return (
|
||||||
<Grid container spacing={3} justifyContent="center">
|
<Grid container spacing={3} justifyContent="center">
|
||||||
{mnemonicWords.map(({ name, index, disabled }) => (
|
{mnemonicWords.map(({ name, index, disabled }) => (
|
||||||
<Grid item xs={2} key={index} onClick={() => onClick?.({ name, index })} data-testid="mnemonicWordTile">
|
<Grid item xs={2} key={index} onClick={() => onClick?.({ name, index })}>
|
||||||
<WordTile
|
<WordTile
|
||||||
mnemonicWord={name}
|
mnemonicWord={name}
|
||||||
index={showIndex ? index : undefined}
|
index={showIndex ? index : undefined}
|
||||||
@@ -79,7 +79,7 @@ const HiddenWord = ({ mnemonicWord }: { mnemonicWord: THiddenMnemonicWord }) =>
|
|||||||
</Box>
|
</Box>
|
||||||
</Fade>
|
</Fade>
|
||||||
</Box>
|
</Box>
|
||||||
<Typography data-testid="wordIndex">{mnemonicWord.index}.</Typography>
|
<Typography>{mnemonicWord.index}.</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export const ConfirmMnemonic = () => {
|
|||||||
<Subtitle subtitle="Enter the mnemonic you wish to create a password for" />
|
<Subtitle subtitle="Enter the mnemonic you wish to create a password for" />
|
||||||
<MnemonicInput mnemonic={localMnemonic} onUpdateMnemonic={(mnc) => setLocalMnemonic(mnc)} error={error} />
|
<MnemonicInput mnemonic={localMnemonic} onUpdateMnemonic={(mnc) => setLocalMnemonic(mnc)} error={error} />
|
||||||
<Button
|
<Button
|
||||||
data-testid="nextToPasswordCreation"
|
|
||||||
size="large"
|
size="large"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -38,7 +37,6 @@ export const ConfirmMnemonic = () => {
|
|||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
data-testid="backToMnemonicSignIn"
|
|
||||||
size="large"
|
size="large"
|
||||||
color="inherit"
|
color="inherit"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ export const ConnectPassword = () => {
|
|||||||
onUpdatePassword={(pswd) => setPassword(pswd)}
|
onUpdatePassword={(pswd) => setPassword(pswd)}
|
||||||
label="Password"
|
label="Password"
|
||||||
autoFocus
|
autoFocus
|
||||||
data-testid="Password"
|
|
||||||
/>
|
/>
|
||||||
<PasswordStrength password={password} onChange={(isStrong) => setIsStrongPassword(isStrong)} />
|
<PasswordStrength password={password} onChange={(isStrong) => setIsStrongPassword(isStrong)} />
|
||||||
</>
|
</>
|
||||||
@@ -56,10 +55,8 @@ export const ConnectPassword = () => {
|
|||||||
password={confirmedPassword}
|
password={confirmedPassword}
|
||||||
onUpdatePassword={(pswd) => setConfirmedPassword(pswd)}
|
onUpdatePassword={(pswd) => setConfirmedPassword(pswd)}
|
||||||
label="Confirm password"
|
label="Confirm password"
|
||||||
data-testid="Confirm Password"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
data-testid="createPasswordButton"
|
|
||||||
size="large"
|
size="large"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
||||||
@@ -68,7 +65,6 @@ export const ConnectPassword = () => {
|
|||||||
{isLoading ? <CircularProgress size={25} /> : 'Create password'}
|
{isLoading ? <CircularProgress size={25} /> : 'Create password'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
data-testid="backToStep1PasswordCreation"
|
|
||||||
size="large"
|
size="large"
|
||||||
color="inherit"
|
color="inherit"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export const CreateMnemonic = () => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
data-testid="iSavedMnemonic"
|
|
||||||
color="primary"
|
color="primary"
|
||||||
disableElevation
|
disableElevation
|
||||||
size="large"
|
size="large"
|
||||||
@@ -34,7 +33,6 @@ export const CreateMnemonic = () => {
|
|||||||
I saved my mnemonic
|
I saved my mnemonic
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
data-testid="backToWelcome"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
resetState();
|
resetState();
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
|
|||||||
@@ -57,14 +57,13 @@ export const CreatePassword = () => {
|
|||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
data-testid="nextStorePassword"
|
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
||||||
onClick={storePassword}
|
onClick={storePassword}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
<Button data-testid="skipPasswordAndSignInWithMnemonic" size="large" color="info" onClick={handleSkip}>
|
<Button size="large" color="info" onClick={handleSkip}>
|
||||||
Skip and sign in with mnemonic
|
Skip and sign in with mnemonic
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ export const ExistingAccount = () => {
|
|||||||
<Title title="Welcome to Nym" />
|
<Title title="Welcome to Nym" />
|
||||||
<SubtitleSlick subtitle="NEXT GENERATION OF PRIVACY" />
|
<SubtitleSlick subtitle="NEXT GENERATION OF PRIVACY" />
|
||||||
<Stack spacing={2} sx={{ width: 300 }}>
|
<Stack spacing={2} sx={{ width: 300 }}>
|
||||||
<Button variant="contained" size="large" onClick={() => navigate('/sign-in-mnemonic')} fullWidth data-testid="signInWithMnemonic">
|
<Button variant="contained" size="large" onClick={() => navigate('/sign-in-mnemonic')} fullWidth>
|
||||||
Sign in with mnemonic
|
Sign in with mnemonic
|
||||||
</Button>
|
</Button>
|
||||||
<Typography sx={{ textAlign: 'center', fontWeight: 600 }}>or</Typography>
|
<Typography sx={{ textAlign: 'center', fontWeight: 600 }}>or</Typography>
|
||||||
<Button variant="contained" size="large" fullWidth onClick={() => navigate('/sign-in-password')} data-testid="signInWithPassword">
|
<Button variant="contained" size="large" fullWidth onClick={() => navigate('/sign-in-password')}>
|
||||||
Sign in with password
|
Sign in with password
|
||||||
</Button>
|
</Button>
|
||||||
<Box display="flex" justifyContent="space-between">
|
<Box display="flex" justifyContent="space-between">
|
||||||
<Button color="inherit" onClick={() => navigate('/')} data-testid="backToWelcomePage">
|
<Button color="inherit" onClick={() => navigate('/')}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="info" onClick={() => navigate('/forgot-password')} data-testid="forgotPassword">
|
<Button color="info" onClick={() => navigate('/forgot-password')}>
|
||||||
Forgot password?
|
Forgot password?
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -39,15 +39,15 @@ export const SignInMnemonic = () => {
|
|||||||
>
|
>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
<MnemonicInput mnemonic={mnemonic} onUpdateMnemonic={(mnc) => setMnemonic(mnc)} error={error} />
|
<MnemonicInput mnemonic={mnemonic} onUpdateMnemonic={(mnc) => setMnemonic(mnc)} error={error} />
|
||||||
<Button variant="contained" size="large" fullWidth type="submit" data-testid="signInWithMnemonicButton">
|
<Button variant="contained" size="large" fullWidth type="submit">
|
||||||
Sign in with mnemonic
|
Sign in with mnemonic
|
||||||
</Button>
|
</Button>
|
||||||
<Box display="flex" justifyContent={passwordExists ? 'center' : 'space-between'}>
|
<Box display="flex" justifyContent={passwordExists ? 'center' : 'space-between'}>
|
||||||
<Button color="inherit" onClick={() => handlePageChange(-1)} data-testid="backToSignInOptions">
|
<Button color="inherit" onClick={() => handlePageChange(-1)}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
{!passwordExists && (
|
{!passwordExists && (
|
||||||
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')} data-testid="goToCreatePassword">
|
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')}>
|
||||||
Create a password
|
Create a password
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export const SignInPassword = () => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
data-testid="signInPasswordButton"
|
|
||||||
variant="contained"
|
variant="contained"
|
||||||
size="large"
|
size="large"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -39,7 +38,6 @@ export const SignInPassword = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Box display="flex" justifyContent="space-between">
|
<Box display="flex" justifyContent="space-between">
|
||||||
<Button
|
<Button
|
||||||
data-testid="skipAndSignInWithMnemonic"
|
|
||||||
color="inherit"
|
color="inherit"
|
||||||
disableElevation
|
disableElevation
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -51,7 +49,6 @@ export const SignInPassword = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
data-testid="forgotPasswordButton"
|
|
||||||
color="info"
|
color="info"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
|
|||||||
@@ -56,11 +56,10 @@ export const VerifyMnemonic = () => {
|
|||||||
size="large"
|
size="large"
|
||||||
disabled={currentSelection !== numberOfRandomWords}
|
disabled={currentSelection !== numberOfRandomWords}
|
||||||
onClick={() => navigate('/create-password')}
|
onClick={() => navigate('/create-password')}
|
||||||
data-testid="nextToStep3"
|
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="inherit" fullWidth size="large" onClick={() => navigate(-1)} data-testid="backToStep1">
|
<Button color="inherit" fullWidth size="large" onClick={() => navigate(-1)}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ export const WelcomeContent: FCWithChildren<{}> = () => {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => navigate('/existing-account')}
|
onClick={() => navigate('/existing-account')}
|
||||||
data-testid="signIn"
|
|
||||||
>
|
>
|
||||||
Sign in
|
Sign in
|
||||||
</Button>
|
</Button>
|
||||||
@@ -30,7 +29,6 @@ export const WelcomeContent: FCWithChildren<{}> = () => {
|
|||||||
disableElevation
|
disableElevation
|
||||||
size="large"
|
size="large"
|
||||||
onClick={() => navigate('/create-mnemonic')}
|
onClick={() => navigate('/create-mnemonic')}
|
||||||
data-testid="createAccount"
|
|
||||||
>
|
>
|
||||||
Create account
|
Create account
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const BalanceCard = () => {
|
|||||||
)}
|
)}
|
||||||
{!userBalance.error && (
|
{!userBalance.error && (
|
||||||
<Typography
|
<Typography
|
||||||
data-testid="nym-balance"
|
data-testid="refresh-success"
|
||||||
sx={{
|
sx={{
|
||||||
color: 'text.primary',
|
color: 'text.primary',
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
|
|||||||
@@ -19,5 +19,5 @@
|
|||||||
"@assets/*": ["../assets/*"]
|
"@assets/*": ["../assets/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target", "wallet-fe-tests"]
|
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
import Balance from '../test/pageobjects/balanceScreen';
|
|
||||||
import Auth from '../test/pageobjects/authScreens';
|
|
||||||
const userData = require('../common/user-data.json');
|
|
||||||
const deleteScript = require('../scripts/deletesavedwallet');
|
|
||||||
const savedWalletScript = require('../scripts/deletesavedwallet.ts');
|
|
||||||
|
|
||||||
class Helpers {
|
|
||||||
// clear wallet data, login, and navigate to QA network
|
|
||||||
freshMnemonicLoginQaNetwork = async () => {
|
|
||||||
await deleteScript;
|
|
||||||
await savedWalletScript;
|
|
||||||
// await Auth.loginWithMnemonic(userData.mnemonic)
|
|
||||||
await this.loginMnemonic();
|
|
||||||
await Balance.selectQa();
|
|
||||||
};
|
|
||||||
|
|
||||||
// login with a mnemonic
|
|
||||||
loginMnemonic = async () => {
|
|
||||||
var decodedmnemonic = this.decodeBase(userData.mnemonic);
|
|
||||||
await Auth.loginWithMnemonic(decodedmnemonic);
|
|
||||||
};
|
|
||||||
|
|
||||||
// click the mnemonic words by index position
|
|
||||||
|
|
||||||
// TO-DO find the best approach
|
|
||||||
mnemonicWordTileIndex = async () => {
|
|
||||||
let mnemonic = await browser.execute(() => {
|
|
||||||
// @ts-ignore: Object is possibly 'null'.
|
|
||||||
return document.getElementById('mnemonicPhrase').innerHTML;
|
|
||||||
});
|
|
||||||
|
|
||||||
let arrayMnemonic = mnemonic.split(' ');
|
|
||||||
|
|
||||||
await this.navigateAndClick(Auth.copyMnemonic);
|
|
||||||
await this.navigateAndClick(Auth.iSavedMnemonic);
|
|
||||||
// verify the mnemonic words in the correct order
|
|
||||||
let mnemonicWordTiles = await Auth.mnemonicWordTile;
|
|
||||||
let wordTileIndex = await Auth.wordIndex;
|
|
||||||
|
|
||||||
const wordsArray: any[] = [];
|
|
||||||
|
|
||||||
for (const word of mnemonicWordTiles) {
|
|
||||||
const wordText = await word.getText();
|
|
||||||
const index = arrayMnemonic.indexOf(wordText);
|
|
||||||
wordsArray.push({ word, index });
|
|
||||||
}
|
|
||||||
for (const index of wordTileIndex) {
|
|
||||||
const indexValue = await index.getText();
|
|
||||||
const match = wordsArray.find((word) => +word.index === +indexValue - 1);
|
|
||||||
if (match) {
|
|
||||||
await match.word.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextButton = await Auth.nextToStep3;
|
|
||||||
//something needs checking over here
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
expect(isNextDisabled).toBe(null);
|
|
||||||
await this.navigateAndClick(Auth.nextToStep3);
|
|
||||||
};
|
|
||||||
|
|
||||||
// decode user data file
|
|
||||||
decodeBase = (input) => {
|
|
||||||
const m = Buffer.from(input, 'base64').toString();
|
|
||||||
return m;
|
|
||||||
};
|
|
||||||
|
|
||||||
// common actions
|
|
||||||
navigateAndClick = async (element) => {
|
|
||||||
await element.waitForClickable({ timeout: 6000 });
|
|
||||||
await element.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
elementVisible = async (element) => {
|
|
||||||
await element.waitForDisplayed({ timeout: 6000 });
|
|
||||||
};
|
|
||||||
|
|
||||||
elementGetText = async (element) => {
|
|
||||||
await element.getText(element);
|
|
||||||
};
|
|
||||||
|
|
||||||
elementClickable = async (element) => {
|
|
||||||
await element.toBeClickable({ timeout: 8000 });
|
|
||||||
};
|
|
||||||
|
|
||||||
addValueToTextField = async (element, value) => {
|
|
||||||
await element.addValue(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyStrictText = async (element, expectedText) => {
|
|
||||||
let error = await element.getText();
|
|
||||||
expect(error).toStrictEqual(expectedText);
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyPartialText = async (element, expectedText) => {
|
|
||||||
let error = await element.getText();
|
|
||||||
expect(error).toContain(expectedText);
|
|
||||||
};
|
|
||||||
|
|
||||||
getAccountAddress = async () => {
|
|
||||||
// fix this in the future to make it generic
|
|
||||||
|
|
||||||
let address = await browser.execute(() => {
|
|
||||||
return document.querySelectorAll("[data-testid='wallet-address']")[0].innerHTML;
|
|
||||||
});
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
//removed those nasty methods as we can now get the correct txs fee from estimation
|
|
||||||
//add cleaner approach
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Helpers();
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
//welcome, sign in, create account
|
|
||||||
homePageErrorMnemonic: 'Error parsing bip39 mnemonic',
|
|
||||||
signInWithoutMnemonic: 'A mnemonic must be provided',
|
|
||||||
signInRandomString: 'mnemonic has a word count that is not a multiple of 6:',
|
|
||||||
signInIncorrectMnemonic: 'mnemonic contains an unknown word',
|
|
||||||
incorrectMnemonicPasswordCreation: 'The mnemonic provided is not valid. Please check the mnemonic',
|
|
||||||
invalidPasswordOnSignIn: 'failed to decrypt the given data with the provided password',
|
|
||||||
signInWithoutPassword: 'A password must be provided',
|
|
||||||
failedToFindWalletFile: 'The wallet file is not found',
|
|
||||||
|
|
||||||
//headers
|
|
||||||
mnemonicSignIn: 'Enter a mnemonic to sign in',
|
|
||||||
passwordSignIn: 'Enter a password to sign in',
|
|
||||||
|
|
||||||
//homePage
|
|
||||||
qaNetwork: 'QA',
|
|
||||||
sandboxNetwork: 'Testnet Sandbox',
|
|
||||||
mainnetNetwork: 'Nym Mainnet',
|
|
||||||
noNym: '0 NYM',
|
|
||||||
|
|
||||||
//send
|
|
||||||
invalidRecipientAddress: '123',
|
|
||||||
recipientAddress: 'n17tj0a0w6v7r2dc54rnkzfza6s8hxs87rj273a5',
|
|
||||||
amountToSend: '1',
|
|
||||||
negativeAmount: '-1',
|
|
||||||
inferiorAmount: '0.0000001',
|
|
||||||
confirmedAmount: '1 NYM',
|
|
||||||
sendDetails: 'Send details',
|
|
||||||
|
|
||||||
// bond
|
|
||||||
host: '1.1.1.1',
|
|
||||||
version: '1.2.1',
|
|
||||||
|
|
||||||
// user incorrect data
|
|
||||||
incorrectMnemonic:
|
|
||||||
'bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else heat giraffe note order sun cradle',
|
|
||||||
randomString: 'thisrandomstring',
|
|
||||||
password: 'updownUPDOWN~#$2',
|
|
||||||
incorrectPassword: '123notvalid',
|
|
||||||
};
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"mnemonic": ""
|
|
||||||
}
|
|
||||||
-6902
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "webdriverio-tests",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "",
|
|
||||||
"private": true,
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"devDependencies": {
|
|
||||||
"@wdio/cli": "^7.25.4",
|
|
||||||
"@wdio/local-runner": "^7.16.16",
|
|
||||||
"@wdio/mocha-framework": "^7.16.15",
|
|
||||||
"@types/mocha": "^9.1.1",
|
|
||||||
"prettier": "2.5.1",
|
|
||||||
"typescript": "^4.6.2",
|
|
||||||
"@nymproject/nym-validator-client": "0.18.0",
|
|
||||||
"@wdio/allure-reporter": "^7.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "wdio run test/wdio.conf.ts",
|
|
||||||
"test-login": "wdio run test/wdio.conf.ts --suite login",
|
|
||||||
"test-signup": "wdio run test/wdio.conf.ts --suite signup",
|
|
||||||
"test-general": "wdio run test/wdio.conf.ts --suite general",
|
|
||||||
"test-balance": "wdio run test/wdio.conf.ts --suite balance",
|
|
||||||
"test-helper": "wdio run test/wdio.conf.ts --suite helper",
|
|
||||||
"test-delegation": "wdio run test/wdio.conf.ts --suite delegation",
|
|
||||||
"run:prettier": "prettier --write ."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
const { exec } = require('child_process');
|
|
||||||
const os = require('os');
|
|
||||||
|
|
||||||
let homedir = os.homedir();
|
|
||||||
|
|
||||||
const doesFileExist = exec(`test -f ${homedir}/.local/share/nym-wallet/saved-wallet.json`, (err, stdout, stderr) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(`${err.message}`);
|
|
||||||
return;
|
|
||||||
} else console.log('File deleted');
|
|
||||||
});
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
#kill existing process
|
|
||||||
kill -9 "$(pgrep aux | grep -E "WebKitWeb|tauri-dri" | awk '{print $2}')"
|
|
||||||
exit 0;
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
class Nav {
|
|
||||||
get lightMode(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='LightModeOutlinedIcon']");
|
|
||||||
}
|
|
||||||
get darkMode(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='ModeNightOutlinedIcon']");
|
|
||||||
}
|
|
||||||
get terminalTitle(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='terminal-header']");
|
|
||||||
}
|
|
||||||
get terminalIcon(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='TerminalIcon']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get balance(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Balance']");
|
|
||||||
}
|
|
||||||
get send(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Send']");
|
|
||||||
}
|
|
||||||
get receive(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Receive']");
|
|
||||||
}
|
|
||||||
get bond(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Bond']");
|
|
||||||
}
|
|
||||||
get unbond(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Unbond']");
|
|
||||||
}
|
|
||||||
get delegation(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Delegation']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get closeIcon(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='CloseIcon']");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default new Nav();
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
import Balance from '../pageobjects/balanceScreen';
|
|
||||||
import Helper from '../../common/helper';
|
|
||||||
const deleteScript = require('../../scripts/deletesavedwallet');
|
|
||||||
|
|
||||||
class Auth {
|
|
||||||
//Welcome landing page
|
|
||||||
get signInButton(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='signIn']");
|
|
||||||
}
|
|
||||||
get createAccount(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='createAccount']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Existing account sign in option page
|
|
||||||
get signInMnemonic(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='signInWithMnemonic']");
|
|
||||||
}
|
|
||||||
get signInPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='signInWithPassword']");
|
|
||||||
}
|
|
||||||
get backToWelcomePage(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToWelcomePage']");
|
|
||||||
}
|
|
||||||
get forgotPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='forgotPassword']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sign in with mnemonic page
|
|
||||||
get mnemonicLoginScreenHeader(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Enter a mnemonic to sign in']");
|
|
||||||
}
|
|
||||||
get mnemonicInput(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='inputMnemonic']");
|
|
||||||
}
|
|
||||||
get signIn(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='signInWithMnemonicButton']");
|
|
||||||
}
|
|
||||||
get backToSignInOptions(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToSignInOptions']");
|
|
||||||
}
|
|
||||||
get revealMnemonic(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Reveal Mnemonic']");
|
|
||||||
}
|
|
||||||
get createPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='goToCreatePassword']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create password step 1/2
|
|
||||||
get backToMnemonicSignIn(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToMnemonicSignIn']");
|
|
||||||
}
|
|
||||||
get nextToPasswordCreation(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='nextToPasswordCreation']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create password step 2/2
|
|
||||||
get password(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Password']");
|
|
||||||
}
|
|
||||||
get confirmPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Confirm password']");
|
|
||||||
}
|
|
||||||
get createPasswordButton(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='createPasswordButton']");
|
|
||||||
}
|
|
||||||
get backToStep1PasswordCreation(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToStep1PasswordCreation']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create account step 1/3
|
|
||||||
get copyMnemonic(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='copyMnemonic']");
|
|
||||||
}
|
|
||||||
get iSavedMnemonic(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='iSavedMnemonic']");
|
|
||||||
}
|
|
||||||
get mnemonicPhrase(): Promise<WebdriverIO.Element> {
|
|
||||||
return $('mnemonicPhrase');
|
|
||||||
}
|
|
||||||
|
|
||||||
get backToWelcomePageFromCreate(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToWelcome']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create account step 2/3
|
|
||||||
get wordIndex(): Promise<WebdriverIO.ElementArray> {
|
|
||||||
return $$("[data-testid='wordIndex']");
|
|
||||||
}
|
|
||||||
get mnemonicWordTile(): Promise<WebdriverIO.ElementArray> {
|
|
||||||
return $$("[data-testid='mnemonicWordTile']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get nextToStep3(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='nextToStep3']");
|
|
||||||
}
|
|
||||||
get backToStep1(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='backToStep1']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create account step 3/3
|
|
||||||
get nextStorePassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='nextStorePassword']");
|
|
||||||
}
|
|
||||||
get skipPasswordAndSignInWithMnemonic(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='skipPasswordAndSignInWithMnemonic']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enter password to sign in
|
|
||||||
get passwordLoginScreenHeader(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Enter a password to sign in']");
|
|
||||||
}
|
|
||||||
get enterPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Enter password']");
|
|
||||||
}
|
|
||||||
get signInPasswordButton(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='signInPasswordButton']");
|
|
||||||
}
|
|
||||||
get backToSignInOptionsFromPassword(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='skipAndSignInWithMnemonic']");
|
|
||||||
}
|
|
||||||
get forgotPasswordButton(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='forgotPasswordButton']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
get error(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='error']");
|
|
||||||
} //check
|
|
||||||
//TO-DO get this bit below working
|
|
||||||
|
|
||||||
getErrorMessage = async () => {
|
|
||||||
await (await this.error).waitForDisplayed({ timeout: 1500 });
|
|
||||||
await (await this.error).getText();
|
|
||||||
};
|
|
||||||
|
|
||||||
//login to the application
|
|
||||||
loginWithMnemonic = async (mnemonic) => {
|
|
||||||
await (await this.signInButton).click();
|
|
||||||
await (await this.signInMnemonic).click();
|
|
||||||
await (await this.mnemonicInput).waitForDisplayed();
|
|
||||||
await (await this.revealMnemonic).click();
|
|
||||||
await (await this.mnemonicInput).addValue(mnemonic);
|
|
||||||
await (await this.signIn).click();
|
|
||||||
await (await Balance.nymBalance).waitForDisplayed({ timeout: 4000 });
|
|
||||||
};
|
|
||||||
|
|
||||||
newMnemonicCreation = async () => {
|
|
||||||
deleteScript;
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(this.createAccount);
|
|
||||||
|
|
||||||
await Helper.mnemonicWordTileIndex();
|
|
||||||
|
|
||||||
const nextButton = await this.nextToStep3;
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
|
|
||||||
expect(isNextDisabled).toBe(null);
|
|
||||||
await Helper.navigateAndClick(this.nextToStep3);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Auth();
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
class Balance {
|
|
||||||
get balance(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='Balance']");
|
|
||||||
}
|
|
||||||
get checkBalance(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='check-balance']");
|
|
||||||
}
|
|
||||||
get nymBalance(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='nym-balance']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get copyAccountId(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='ContentCopyIcon']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get walletAddress(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='wallet-address']");
|
|
||||||
}
|
|
||||||
|
|
||||||
get networkDropdown(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='ArrowDropDownIcon']");
|
|
||||||
}
|
|
||||||
get networkEnv(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='networkEnv']");
|
|
||||||
}
|
|
||||||
get networkSelectQa(): Promise<WebdriverIO.Element> {
|
|
||||||
return $("[data-testid='QA']");
|
|
||||||
}
|
|
||||||
|
|
||||||
selectQa = async () => {
|
|
||||||
await (await this.networkDropdown).waitForDisplayed({ timeout: 4000 });
|
|
||||||
await (await this.networkDropdown).click();
|
|
||||||
await (await this.networkSelectQa).waitForClickable({ timeout: 4000 });
|
|
||||||
await (await this.networkSelectQa).click();
|
|
||||||
await (await this.networkEnv).waitForClickable({ timeout: 2000 });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export default new Balance();
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
class Bond {
|
|
||||||
// Bonding
|
|
||||||
|
|
||||||
get bondTitle() {
|
|
||||||
return $("[data-testid='Bond']");
|
|
||||||
}
|
|
||||||
get mixnodeRadio() {
|
|
||||||
return $("[data-testid='mix-node']");
|
|
||||||
}
|
|
||||||
get gatewayRadio() {
|
|
||||||
return $("[data-testid='gate-way']");
|
|
||||||
}
|
|
||||||
get fundsAlert() {
|
|
||||||
return $("[data-testid='fundsAlert']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unbonding
|
|
||||||
|
|
||||||
get unbondTitle() {
|
|
||||||
return $("[data-testid='Unbond']");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default new Bond();
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
class Delegation {
|
|
||||||
get delegationTitle() {
|
|
||||||
return $("[data-testid='Delegation']");
|
|
||||||
}
|
|
||||||
get delegateStakeButton() {
|
|
||||||
return $("[data-testid='Delegate stake']");
|
|
||||||
}
|
|
||||||
get delegateModalHeader() {
|
|
||||||
return $("[data-testid='Delegate']");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Delegation();
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
class Receive {
|
|
||||||
get receiveNymTitle() {
|
|
||||||
return $("[data-testid='Receive NYM']");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Receive();
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
class Send {
|
|
||||||
// send nym form
|
|
||||||
get sendHeader() {
|
|
||||||
return $("[data-testid='Send']");
|
|
||||||
}
|
|
||||||
get recipientAddress() {
|
|
||||||
return $("[data-testid='recipientAddress']");
|
|
||||||
}
|
|
||||||
// get sendAmount() { return $("[data-testid='Amount']") }
|
|
||||||
get sendAmount() {
|
|
||||||
return $('#mui-5');
|
|
||||||
} // TO-DO fix this selector, using #mui-5 isn't a good solution
|
|
||||||
get next() {
|
|
||||||
return $("[data-testid='Next']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// confirm transaction modal
|
|
||||||
get sendDetailsHeader() {
|
|
||||||
return $("[data-testid='Send details']");
|
|
||||||
}
|
|
||||||
get from() {
|
|
||||||
return $('/html/body/div[2]/div[3]/div[2]/div[1]/div[1]');
|
|
||||||
}
|
|
||||||
get to() {
|
|
||||||
return $('/html/body/div[2]/div[3]/div[2]/div[2]');
|
|
||||||
}
|
|
||||||
get amount() {
|
|
||||||
return $('/html/body/div[2]/div[3]/div[2]/div[3]');
|
|
||||||
}
|
|
||||||
get fee() {
|
|
||||||
return $('/html/body/div[2]/div[3]/div[2]/div[4]');
|
|
||||||
}
|
|
||||||
|
|
||||||
get confirm() {
|
|
||||||
return $("[data-testid='Confirm']");
|
|
||||||
}
|
|
||||||
|
|
||||||
// transaction sent
|
|
||||||
get viewOnBlockchain() {
|
|
||||||
return $("[data-testid='viewOnBlockchain']");
|
|
||||||
}
|
|
||||||
get done() {
|
|
||||||
return $("[data-testid='Done']");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default new Send();
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import Helper from '../../../common/helper';
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
|
|
||||||
describe('Balance screen displays correctly', () => {
|
|
||||||
it('selecting qa network', async () => {
|
|
||||||
//log in
|
|
||||||
await Helper.loginMnemonic();
|
|
||||||
// select QA network
|
|
||||||
await Helper.navigateAndClick(Balance.networkDropdown);
|
|
||||||
await Helper.navigateAndClick(Balance.networkSelectQa);
|
|
||||||
// verifty QA network has been selected properly
|
|
||||||
await Helper.verifyStrictText(Balance.networkEnv, textConstants.qaNetwork);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('copy the account id', async () => {
|
|
||||||
// ensure the account number contains *something*
|
|
||||||
await Helper.elementVisible(Balance.walletAddress);
|
|
||||||
|
|
||||||
let getaccountAddress = await Helper.getAccountAddress();
|
|
||||||
|
|
||||||
console.log(getaccountAddress);
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(Balance.copyAccountId);
|
|
||||||
// disclaimer - I think if it's in clipboard we can use the below...
|
|
||||||
// let's try using the clipboard api here - TODO
|
|
||||||
|
|
||||||
// let clipboard = await browser.execute(() => {
|
|
||||||
//
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// })
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Nav from '../../pageobjects/appNavConstants';
|
|
||||||
import Delegation from '../../pageobjects/delegationScreen';
|
|
||||||
import Send from '../../pageobjects/sendScreen';
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
const userData = require('../../../common/user-data.json');
|
|
||||||
|
|
||||||
describe('Delegate to a mixnode', () => {
|
|
||||||
it('entering an invalid node identity key', async () => {
|
|
||||||
//login and navigate to the screen
|
|
||||||
await Helper.freshMnemonicLoginQaNetwork();
|
|
||||||
await Helper.navigateAndClick(Nav.delegation);
|
|
||||||
await Helper.elementVisible(Delegation.delegationTitle);
|
|
||||||
// TO-DO enter an invalid node
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Nav from '../../pageobjects/appNavConstants';
|
|
||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import Send from '../../pageobjects/sendScreen';
|
|
||||||
import Receive from '../../pageobjects/receiveScreen';
|
|
||||||
import Bond from '../../pageobjects/bondScreen';
|
|
||||||
import Delegation from '../../pageobjects/delegationScreen';
|
|
||||||
const userData = require('../../../common/user-data.json');
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
|
|
||||||
describe('Nav Items behave correctly', () => {
|
|
||||||
it('switch from light to dark mode and back', async () => {
|
|
||||||
//log in()
|
|
||||||
await Helper.freshMnemonicLoginQaNetwork();
|
|
||||||
// click on different modes
|
|
||||||
await Helper.navigateAndClick(Nav.lightMode);
|
|
||||||
await Helper.navigateAndClick(Nav.darkMode);
|
|
||||||
await Helper.elementVisible(Nav.lightMode);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('clicking terminal opens the modal', async () => {
|
|
||||||
// ensure the terminal button opens the terminal
|
|
||||||
await Helper.elementVisible(Nav.terminalIcon);
|
|
||||||
await Helper.navigateAndClick(Nav.terminalIcon);
|
|
||||||
await Helper.elementVisible(Nav.terminalTitle);
|
|
||||||
await Helper.verifyPartialText(Nav.terminalTitle, 'Terminal');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Menu items lead to correct screen', () => {
|
|
||||||
//TO-DO none of this works
|
|
||||||
//check each menu item opens the right screen/modal
|
|
||||||
it('check Balance link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.balance);
|
|
||||||
await Helper.verifyPartialText(Balance.balance, 'Balance');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('check Send link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.send);
|
|
||||||
await Helper.verifyPartialText(Send.sendHeader, 'Send');
|
|
||||||
await Helper.navigateAndClick(Nav.closeIcon);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('check Receive link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.receive);
|
|
||||||
await Helper.verifyPartialText(Receive.receiveNymTitle, 'Receive NYM');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('check Bond link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.bond);
|
|
||||||
await Helper.verifyPartialText(Bond.bondTitle, 'Bond');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('check Unbond link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.unbond);
|
|
||||||
await Helper.verifyPartialText(Bond.unbondTitle, 'Unbond');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('check Delegation link works', async () => {
|
|
||||||
await Helper.navigateAndClick(Nav.delegation);
|
|
||||||
await Helper.verifyPartialText(Delegation.delegationTitle, 'Delegation');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Nav from '../../pageobjects/appNavConstants';
|
|
||||||
import Send from '../../pageobjects/sendScreen';
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
const userData = require('../../../common/user-data.json');
|
|
||||||
|
|
||||||
describe.skip('Send modal functions correctly', () => {
|
|
||||||
it('entering an invalid recipient address shows error', async () => {
|
|
||||||
// sign in with mnemonic and select QA
|
|
||||||
await Helper.freshMnemonicLoginQaNetwork();
|
|
||||||
// click on send and check modal appears
|
|
||||||
await Helper.navigateAndClick(Nav.send);
|
|
||||||
await Helper.elementVisible(Send.sendHeader);
|
|
||||||
// add an invalid recipient address
|
|
||||||
await Helper.addValueToTextField(Send.recipientAddress, textConstants.invalidRecipientAddress);
|
|
||||||
// TO-DO -- question: should there not be an error message before clicking on Next to warn that the address is invalid?
|
|
||||||
});
|
|
||||||
|
|
||||||
it('entering an valid recipient address with negative amount value shows error', async () => {
|
|
||||||
await Helper.navigateAndClick(Send.recipientAddress);
|
|
||||||
// TO-DO figure out how to clear a text field before adding new value
|
|
||||||
await Send.recipientAddress.clearValue();
|
|
||||||
await Helper.addValueToTextField(Send.recipientAddress, userData.receiver_address);
|
|
||||||
await Helper.navigateAndClick(Send.sendAmount);
|
|
||||||
await Helper.addValueToTextField(Send.sendAmount, textConstants.negativeAmount);
|
|
||||||
//next button is still disabled and error message appears
|
|
||||||
const nextButton = await Send.next;
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
expect(isNextDisabled).toBe('true');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('enter a valid recipient and value', async () => {
|
|
||||||
// enter valid data
|
|
||||||
await Helper.addValueToTextField(Send.recipientAddress, userData.receiver_address);
|
|
||||||
const getCurrentBalance = await (await Balance.nymBalance).getText();
|
|
||||||
await Helper.addValueToTextField(Send.sendAmount, textConstants.amountToSend);
|
|
||||||
// click on next and verify details
|
|
||||||
await Helper.navigateAndClick(Send.next);
|
|
||||||
const fee = await (await Send.fee).getText();
|
|
||||||
await Helper.verifyPartialText(Send.sendDetailsHeader, textConstants.sendDetails);
|
|
||||||
await Helper.verifyPartialText(Send.amount, textConstants.confirmedAmount);
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(Send.confirm);
|
|
||||||
await Helper.elementVisible(Send.viewOnBlockchain);
|
|
||||||
await Helper.elementClickable(Send.done);
|
|
||||||
|
|
||||||
// calculate the transaction and verify it has been correctly executed
|
|
||||||
let sumCost = await Helper.calculateFees(getCurrentBalance, fee, textConstants.amountToSend, true);
|
|
||||||
const getNewBalance = await (await Balance.nymBalance).getText();
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(Send.done);
|
|
||||||
// TO-DO the following fails with "TypeError: elem[prop] is not a function"
|
|
||||||
expect(getNewBalance).toEqual(sumCost);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
|
|
||||||
describe('Create a new account and verify login', () => {
|
|
||||||
it('generate new mnemonic and verify mnemonic words', async () => {
|
|
||||||
// test to check new mnemonic creation
|
|
||||||
// will refine shortly
|
|
||||||
await browser.pause(1500);
|
|
||||||
|
|
||||||
await Auth.newMnemonicCreation();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import ValidatorClient from '@nymproject/nym-validator-client';
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
|
|
||||||
describe('Wallet sign in functionality with mnemonic', () => {
|
|
||||||
it('get to the sign in with mnemonic screen', async () => {
|
|
||||||
// click through to reach the mnemonic sign in
|
|
||||||
await Helper.navigateAndClick(Auth.signInButton);
|
|
||||||
await Helper.navigateAndClick(Auth.signInMnemonic);
|
|
||||||
// verify you are on the right screen by confirming the header
|
|
||||||
await Helper.verifyStrictText(Auth.mnemonicLoginScreenHeader, textConstants.mnemonicSignIn);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign in with no mnemonic throws error', async () => {
|
|
||||||
await Helper.navigateAndClick(Auth.signIn);
|
|
||||||
// wait for error
|
|
||||||
await Helper.elementVisible(Auth.error);
|
|
||||||
// verify error has the correct message
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.signInWithoutMnemonic);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign in with incorrect mnemonic throws error', async () => {
|
|
||||||
// enter an incorrect mnemonic string
|
|
||||||
await Helper.navigateAndClick(Auth.revealMnemonic);
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.incorrectMnemonic);
|
|
||||||
await Helper.navigateAndClick(Auth.signIn);
|
|
||||||
// verifty error message is correct
|
|
||||||
await Helper.verifyPartialText(Auth.error, textConstants.signInIncorrectMnemonic);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign in with random string throws error', async () => {
|
|
||||||
await Helper.navigateAndClick(Auth.revealMnemonic);
|
|
||||||
// enter a random string not in mnemonic "format"
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.randomString);
|
|
||||||
await Helper.navigateAndClick(Auth.signIn);
|
|
||||||
// verifty error message is correct
|
|
||||||
await Helper.verifyPartialText(Auth.error, textConstants.signInRandomString);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should sign in with valid credentials', async () => {
|
|
||||||
// create new mnemonic
|
|
||||||
const randomMnemonic = ValidatorClient.randomMnemonic();
|
|
||||||
// enter mnemonic
|
|
||||||
await Helper.navigateAndClick(Auth.revealMnemonic);
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, randomMnemonic);
|
|
||||||
await Helper.navigateAndClick(Auth.signIn);
|
|
||||||
// verify successful login, balance is visible
|
|
||||||
await Helper.elementVisible(Balance.balance);
|
|
||||||
// TO-DO this value below is sometimes returning ""
|
|
||||||
await Helper.verifyStrictText(Balance.nymBalance, textConstants.noNym);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
import ValidatorClient from '@nymproject/nym-validator-client';
|
|
||||||
const deleteScript = require('../../../scripts/deletesavedwallet');
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
|
|
||||||
describe('Create password for existing account and use it to sign in', () => {
|
|
||||||
it('enter incorrect mnemonic', async () => {
|
|
||||||
//click through sign in
|
|
||||||
await Helper.navigateAndClick(Auth.signInButton);
|
|
||||||
await Helper.navigateAndClick(Auth.signInMnemonic);
|
|
||||||
//instead of entering mnemonic, click on create a password
|
|
||||||
await Helper.navigateAndClick(Auth.createPassword);
|
|
||||||
//enter incorrect mnemonic
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.incorrectMnemonic);
|
|
||||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation);
|
|
||||||
|
|
||||||
// assert error message is correct
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.incorrectMnemonicPasswordCreation);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('enter random string', async () => {
|
|
||||||
// enter random string as mnemonic
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, textConstants.randomString);
|
|
||||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation);
|
|
||||||
// assert error is correct
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.incorrectMnemonicPasswordCreation);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('enter correct mnemonic', async () => {
|
|
||||||
// generate random mnemonic in the backend
|
|
||||||
const randomMnemonic = ValidatorClient.randomMnemonic();
|
|
||||||
|
|
||||||
// use it to continue with password creation flow
|
|
||||||
await Helper.navigateAndClick(Auth.backToMnemonicSignIn);
|
|
||||||
await Helper.navigateAndClick(Auth.createPassword);
|
|
||||||
await Helper.navigateAndClick(Auth.revealMnemonic);
|
|
||||||
await Helper.addValueToTextField(Auth.mnemonicInput, randomMnemonic);
|
|
||||||
await Helper.navigateAndClick(Auth.nextToPasswordCreation);
|
|
||||||
await Helper.elementVisible(Auth.password);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('create an invalid password', async () => {
|
|
||||||
// type an invalid password in both fields
|
|
||||||
await Helper.addValueToTextField(Auth.password, textConstants.incorrectPassword);
|
|
||||||
await Helper.navigateAndClick(Auth.confirmPassword);
|
|
||||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.incorrectPassword);
|
|
||||||
// ensure the button to proceed is still disabled
|
|
||||||
const nextButton = await Auth.createPasswordButton;
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
expect(isNextDisabled).toBe('true');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('create a valid password', async () => {
|
|
||||||
// type a valid password in both fields
|
|
||||||
await Helper.navigateAndClick(Auth.password);
|
|
||||||
await Helper.addValueToTextField(Auth.password, textConstants.password);
|
|
||||||
await Helper.navigateAndClick(Auth.confirmPassword);
|
|
||||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.password);
|
|
||||||
// verify the password is created and the next screen is visible
|
|
||||||
await Helper.navigateAndClick(Auth.createPasswordButton);
|
|
||||||
await Helper.verifyStrictText(Auth.passwordLoginScreenHeader, textConstants.passwordSignIn);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign in with no password throws error', async () => {
|
|
||||||
//click sign without entering a password
|
|
||||||
await Helper.navigateAndClick(Auth.signInPasswordButton);
|
|
||||||
// wait for error
|
|
||||||
await Helper.elementVisible(Auth.error);
|
|
||||||
// verify error has the correct message
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.signInWithoutPassword);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sign in with invalid password throws error', async () => {
|
|
||||||
// enter invalid password
|
|
||||||
await Helper.addValueToTextField(Auth.enterPassword, textConstants.incorrectPassword);
|
|
||||||
await Helper.navigateAndClick(Auth.signInPasswordButton);
|
|
||||||
// wait for error
|
|
||||||
await Helper.elementVisible(Auth.error);
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.invalidPasswordOnSignIn);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Wallet sign in functionality without creating password', () => {
|
|
||||||
it('sign in with invalid password and no saved wallet.json file throws error', async () => {
|
|
||||||
//click through sign without entering a password
|
|
||||||
await Helper.navigateAndClick(Auth.signInButton);
|
|
||||||
await Helper.navigateAndClick(Auth.signInPassword);
|
|
||||||
// enter invalid password
|
|
||||||
await Helper.addValueToTextField(Auth.enterPassword, textConstants.incorrectPassword);
|
|
||||||
await Helper.navigateAndClick(Auth.signInPasswordButton);
|
|
||||||
// wait for error
|
|
||||||
await Helper.elementVisible(Auth.error);
|
|
||||||
// verify error has the correct message
|
|
||||||
await Helper.verifyStrictText(Auth.error, textConstants.failedToFindWalletFile);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import Auth from '../../pageobjects/authScreens';
|
|
||||||
import Balance from '../../pageobjects/balanceScreen';
|
|
||||||
const textConstants = require('../../../common/text-constants');
|
|
||||||
const userData = require('../../../common/user-data.json');
|
|
||||||
const deleteScript = require('../../../scripts/deletesavedwallet');
|
|
||||||
const Helper = require('../../../common/helper');
|
|
||||||
|
|
||||||
// TO-DO figure out how to not repeat steps but also start a fresh test on each run
|
|
||||||
|
|
||||||
describe('Create a new account negative scenarios', () => {
|
|
||||||
it('generate new mnemonic and verify mnemonic words', async () => {
|
|
||||||
//create the new mnemoinc
|
|
||||||
await Auth.newMnemonicCreation();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('click skip password', async () => {
|
|
||||||
// click on skip password creation
|
|
||||||
await Helper.navigateAndClick(Auth.nextToStep3);
|
|
||||||
await Helper.navigateAndClick(Auth.skipPasswordAndSignInWithMnemonic);
|
|
||||||
// can see mnemonic login page
|
|
||||||
await Helper.elementVisible(Auth.mnemonicInput);
|
|
||||||
await Helper.navigateAndClick(Auth.backToSignInOptions);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('set up invalid password for new account', async () => {
|
|
||||||
// enter invalid password in both fields
|
|
||||||
await Helper.navigateAndClick(Auth.password);
|
|
||||||
await Helper.addValueToTextField(Auth.password, textConstants.incorrectPassword);
|
|
||||||
await Helper.navigateAndClick(Auth.confirmPassword);
|
|
||||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.incorrectPassword);
|
|
||||||
// verify that the 'next' button is still disabled
|
|
||||||
const nextButton = await Auth.nextStorePassword;
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
expect(isNextDisabled).toBe('true');
|
|
||||||
|
|
||||||
await browser.reloadSession();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip('Create a new account and verify login', () => {
|
|
||||||
it('generate new mnemonic and verify mnemonic words', async () => {
|
|
||||||
await Auth.newMnemonicCreation();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('set up valid password for new account', async () => {
|
|
||||||
// enter a valid password in both fields
|
|
||||||
await Helper.navigateAndClick(Auth.password);
|
|
||||||
await Helper.addValueToTextField(Auth.password, textConstants.password);
|
|
||||||
await browser.pause(3000);
|
|
||||||
await Helper.navigateAndClick(Auth.confirmPassword);
|
|
||||||
await Helper.addValueToTextField(Auth.confirmPassword, textConstants.password);
|
|
||||||
await browser.pause(3000);
|
|
||||||
// verify that the 'next' button is clickable
|
|
||||||
const nextButton = await Auth.nextStorePassword;
|
|
||||||
const isNextDisabled = await nextButton.getAttribute('disabled');
|
|
||||||
expect(isNextDisabled).toBe(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('proceed to login with newly created password', async () => {
|
|
||||||
// login with a password
|
|
||||||
await Helper.navigateAndClick(Auth.nextStorePassword);
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(Auth.enterPassword);
|
|
||||||
await Helper.addValueToTextField(Auth.enterPassword, textConstants.password);
|
|
||||||
|
|
||||||
await Helper.navigateAndClick(Auth.signInPasswordButton);
|
|
||||||
|
|
||||||
await Helper.elementVisible(Balance.balance);
|
|
||||||
//new accounts will always default to mainnet, so 0 balance
|
|
||||||
await Helper.verifyStrictText(Balance.nymBalance, textConstants.noNym);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"types": ["node", "webdriverio/async", "@wdio/mocha-framework", "expect-webdriverio"],
|
|
||||||
"target": "ES5"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
const os = require('os');
|
|
||||||
const path = require('path');
|
|
||||||
const deleteSavedWallet = require('../scripts/deletesavedwallet');
|
|
||||||
const { spawn, spawnSync } = require('child_process');
|
|
||||||
|
|
||||||
//insert path to binary
|
|
||||||
const nym_path = '../target/debug/nym-wallet';
|
|
||||||
// this one below will run the prod version aka without QA netwo0rk option
|
|
||||||
// const nym_path = '../target/release/nym-wallet'
|
|
||||||
|
|
||||||
let tauriDriver: any;
|
|
||||||
|
|
||||||
exports.config = {
|
|
||||||
autoCompileOpts: {
|
|
||||||
autoCompile: true,
|
|
||||||
tsNodeOpts: {
|
|
||||||
transpileOnly: true,
|
|
||||||
project: 'test/tsconfig.json',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
specs: ['./test/specs/**/*.ts'],
|
|
||||||
|
|
||||||
suites: {
|
|
||||||
signup: ['./test/specs/signup/*.ts'],
|
|
||||||
login: ['./test/specs/login/*.ts'],
|
|
||||||
balance: ['./test/specs/balance/*.ts'],
|
|
||||||
general: ['./test/specs/general/*.ts'],
|
|
||||||
send: ['./test/specs/bond/*.ts'],
|
|
||||||
delegation: ['./test/specs/delegation/*.ts'],
|
|
||||||
helper: ['./test/specs/helpers/*.ts'],
|
|
||||||
},
|
|
||||||
|
|
||||||
exclude: [
|
|
||||||
// 'path/to/excluded/files'
|
|
||||||
],
|
|
||||||
maxInstances: 1,
|
|
||||||
capabilities: [
|
|
||||||
{
|
|
||||||
maxInstances: 1,
|
|
||||||
'tauri:options': {
|
|
||||||
application: nym_path,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// ===================
|
|
||||||
// Test Configurations
|
|
||||||
// ===================
|
|
||||||
|
|
||||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
|
||||||
logLevel: 'error',
|
|
||||||
bail: 0,
|
|
||||||
framework: 'mocha',
|
|
||||||
// reporters: ['spec'],
|
|
||||||
mochaOpts: {
|
|
||||||
ui: 'bdd',
|
|
||||||
timeout: 60000,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Reporting tool and settings
|
|
||||||
|
|
||||||
reporters: [
|
|
||||||
[
|
|
||||||
'allure',
|
|
||||||
{
|
|
||||||
outputDir: 'allure-results',
|
|
||||||
disableWebdriverStepsReporting: true,
|
|
||||||
disableWebdriverScreenshotsReporting: true,
|
|
||||||
// useCucumberStepReporter: true,
|
|
||||||
// disableMochaHooks: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
// Things to run before/after each test session
|
|
||||||
|
|
||||||
onPrepare: () => {
|
|
||||||
let scriptpath = process.cwd() + '/scripts/killprocess.sh';
|
|
||||||
spawn('bash', [scriptpath]);
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeSession: () => {
|
|
||||||
tauriDriver = spawn(path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'), [], {
|
|
||||||
stdio: [null, process.stdout, process.stderr],
|
|
||||||
});
|
|
||||||
|
|
||||||
//before the session - if any issues arise with wallet data, let's remove existing saved files
|
|
||||||
deleteSavedWallet;
|
|
||||||
},
|
|
||||||
|
|
||||||
afterEach: function (test) {
|
|
||||||
if (test.error !== undefined) {
|
|
||||||
browser.takeScreenshot();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// clean up the `tauri-driver` process we spawned at the start of the session
|
|
||||||
afterSession: () => tauriDriver.kill(),
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<!--
|
||||||
|
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Nym Wallet Webdriverio testsuite
|
||||||
|
|
||||||
|
A webdriverio test suite implementation using tauri driver
|
||||||
|
with a page object model design. This is to provide quick iterative feedback
|
||||||
|
on the UI of the nym wallet. Currently, tauri-driver is available to run on Windows and Linux machines.
|
||||||
|
|
||||||
|
## Installation prerequisites
|
||||||
|
|
||||||
|
- `Yarn`
|
||||||
|
- `NodeJS >= v16.8.0`
|
||||||
|
- `Rust & cargo >= v1.56.1`
|
||||||
|
- `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.json 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 `tauri-wallet/target/*/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.json`
|
||||||
|
- `check the wdio.conf.cjs to see the test execution along with the 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" : "1",
|
||||||
|
"identity_key_to_delegate_mix_node": "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:newuser`
|
||||||
|
|
||||||
|
Tests are categorised and run by their pages, they follow a sequential flow, if one test case fails before the next execution it may derail the next test.
|
||||||
|
|
||||||
|
//todo improve in near future
|
||||||
|
|
||||||
|
## Test reporting
|
||||||
|
|
||||||
|
Currently the tests use allure reporting, the configuration can be altered in the `wdio.conf.cjs`. At present it takes snapshots of any failing tests, the test output run can be seen in the allure-results directory
|
||||||
|
Tests ouput:
|
||||||
|
|
||||||
|
- <guid-testuite.xml>
|
||||||
|
- <guid-attachment.png>
|
||||||
|
|
||||||
|
If any tests fail in their test run it will produce the stack trace error along with the test in question
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
_Disclaimer_: Still WIP
|
||||||
|
|
||||||
|
Implement error handling/ beforeTest() - validating json file exists with data for test execution
|
||||||
|
|
||||||
|
Currently this is dev'd against a Linux based OS, not tested against windows yet.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
targets: {
|
||||||
|
node: "14",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
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",
|
||||||
|
walletSuccess:
|
||||||
|
"Please store your mnemonic in a safe place. You'll need it to access your wallet",
|
||||||
|
|
||||||
|
//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.",
|
||||||
|
unbondMixNode: "UNBOND",
|
||||||
|
|
||||||
|
//delegatePage // undelegatePage
|
||||||
|
delegateHeaderText: "Delegate\nDelegate to mixnode",
|
||||||
|
nodeIdentityValidationText: "identity is a required field",
|
||||||
|
amountValidationText: "amount is a required field",
|
||||||
|
undelegateHeaderText: "Undelegate from a mixnode or gateway",
|
||||||
|
delegationComplete: "Delegation complete",
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"mnemonic": "value",
|
||||||
|
"punk_address": "",
|
||||||
|
"receiver_address": "",
|
||||||
|
"amount_to_send": "",
|
||||||
|
"identity_key_to_delegate_mix_node": "",
|
||||||
|
"identity_key_to_delegate_gateway": "",
|
||||||
|
"delegate_amount": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
//todo need to improve calculation - WIP
|
||||||
|
calculateFees = async (beforeBalance, transactionFee, amount, isSend) => {
|
||||||
|
let fee;
|
||||||
|
|
||||||
|
if (isSend) {
|
||||||
|
//send transaction
|
||||||
|
fee = transactionFee.split(/\s+/)[0];
|
||||||
|
} else {
|
||||||
|
//delegate transaction
|
||||||
|
fee = transactionFee.split(/\s+/)[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentBalance = beforeBalance.split(/\s+/)[0];
|
||||||
|
|
||||||
|
const castCurrentBalance = parseFloat(currentBalance).toFixed(5);
|
||||||
|
const transCost = +parseFloat(amount) + +parseFloat(fee).toFixed(5);
|
||||||
|
|
||||||
|
let sum = parseFloat(castCurrentBalance) - parseFloat(transCost);
|
||||||
|
return sum.toFixed(5);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Helpers();
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"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 sendreceive",
|
||||||
|
"test:home": "wdio run wdio.conf.cjs --suite home",
|
||||||
|
"test:bond": "wdio run wdio.conf.cjs --suite bond",
|
||||||
|
"test:delegate": "wdio run wdio.conf.cjs --suite delegate",
|
||||||
|
"test:newuser": "wdio run wdio.conf.cjs --suite newuser",
|
||||||
|
"run:prettier": "prettier --write ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^16.11.0",
|
||||||
|
"@wdio/allure-reporter": "^7.16.1",
|
||||||
|
"@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",
|
||||||
|
"prettier": "2.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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 selectAdvancedOptions() {
|
||||||
|
return $("[type='checkbox']");
|
||||||
|
}
|
||||||
|
get mixPort() {
|
||||||
|
return $("#mixPort");
|
||||||
|
}
|
||||||
|
get verlocPort() {
|
||||||
|
return $("#verlocPort");
|
||||||
|
}
|
||||||
|
get httpApiPort() {
|
||||||
|
return $("#httpApiPort");
|
||||||
|
}
|
||||||
|
get bondButton() {
|
||||||
|
return $("[data-testid='bond-button']");
|
||||||
|
}
|
||||||
|
get unBondButton() {
|
||||||
|
return $("[data-testid='un-bond']");
|
||||||
|
}
|
||||||
|
get unBond() {
|
||||||
|
return $("[data-testid='bond-noded']");
|
||||||
|
}
|
||||||
|
get unBondWarning() {
|
||||||
|
return $("div.MuiAlert-message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new WalletBond();
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
class WalletCreate {
|
||||||
|
get createAccount() {
|
||||||
|
return $("[href='#']");
|
||||||
|
}
|
||||||
|
get create() {
|
||||||
|
return $("[data-testid='create-button']");
|
||||||
|
}
|
||||||
|
get accountCreatedSuccessfully() {
|
||||||
|
return $("[data-testid='mnemonic-warning']");
|
||||||
|
}
|
||||||
|
get walletMnemonicValue() {
|
||||||
|
return $("[data-testid='mnemonic-phrase']");
|
||||||
|
}
|
||||||
|
get punkAddress() {
|
||||||
|
return $("[data-testid='wallet-address']");
|
||||||
|
}
|
||||||
|
get backToSignIn() {
|
||||||
|
return $("[data-testid='sign-in-button']");
|
||||||
|
}
|
||||||
|
get signInButton() {
|
||||||
|
return $("[type='submit']");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = new WalletCreate();
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
class WalletDelegate {
|
||||||
|
get header() {
|
||||||
|
return $("[data-testid='Delegate']");
|
||||||
|
}
|
||||||
|
get nodeIdentity() {
|
||||||
|
return $("#identity");
|
||||||
|
}
|
||||||
|
get amountToDelegate() {
|
||||||
|
return $("#amount");
|
||||||
|
}
|
||||||
|
get identityValidation() {
|
||||||
|
return $("#identity-helper-text");
|
||||||
|
}
|
||||||
|
get amountToDelegateValidation() {
|
||||||
|
return $("#amount-helper-text");
|
||||||
|
}
|
||||||
|
get delegateStakeButton() {
|
||||||
|
return $("[data-testid='delegate-button']");
|
||||||
|
}
|
||||||
|
get mixNodeRadioButton() {
|
||||||
|
return $("[data-testid='mix-node']");
|
||||||
|
}
|
||||||
|
get gateWayRadioButton() {
|
||||||
|
return $("[data-testid='gate-way']");
|
||||||
|
}
|
||||||
|
get successfullyDelegate() {
|
||||||
|
return $("[data-testid='delegate-success']");
|
||||||
|
}
|
||||||
|
get finishButton() {
|
||||||
|
return $("[data-testid='finish-button']");
|
||||||
|
}
|
||||||
|
get transactionFeeAmount() {
|
||||||
|
return $("[data-testid='fee-amount']");
|
||||||
|
}
|
||||||
|
get accountBalance() {
|
||||||
|
return $("[data-testid='account-balance']");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Undelegate
|
||||||
|
get unDelegateHeader() {
|
||||||
|
return $("[data-testid='Undelegate']");
|
||||||
|
}
|
||||||
|
get unNodeIdentity() {
|
||||||
|
return $("[name='identity']");
|
||||||
|
}
|
||||||
|
get unDelegateFeeText() {
|
||||||
|
return $("[data-testid='fee-amount']");
|
||||||
|
}
|
||||||
|
get unDelegateGatewayRadioButton() {
|
||||||
|
return $("[data-testid='gate-way']");
|
||||||
|
}
|
||||||
|
get unMixNodeRadioButton() {
|
||||||
|
return $("[data-testid='mix-node']");
|
||||||
|
}
|
||||||
|
get unDelegateButton() {
|
||||||
|
return $("[data-testid='submit-button']");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new WalletDelegate();
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
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 $("");
|
||||||
|
}
|
||||||
|
get punkAddress() {
|
||||||
|
return $("[data-testid='wallet-address']");
|
||||||
|
}
|
||||||
|
get accountBalance() {
|
||||||
|
return $("[data-testid='account-balance']");
|
||||||
|
}
|
||||||
|
get balanceButton() {
|
||||||
|
return $("[href='/balance']");
|
||||||
|
}
|
||||||
|
get sendButton() {
|
||||||
|
return $("[href='/send']");
|
||||||
|
}
|
||||||
|
get receiveButton() {
|
||||||
|
return $("[href='/receive']");
|
||||||
|
}
|
||||||
|
get bondButton() {
|
||||||
|
return $("[href='/bond']");
|
||||||
|
}
|
||||||
|
get unBondButton() {
|
||||||
|
return $("[href='/unbond']");
|
||||||
|
}
|
||||||
|
get delegateButton() {
|
||||||
|
return $("[href='/delegate']");
|
||||||
|
}
|
||||||
|
get unDelegateButton() {
|
||||||
|
return $("[href='/undelegate']");
|
||||||
|
}
|
||||||
|
get logOutButton() {
|
||||||
|
return $("[data-testid='log-out']");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new WalletHome();
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
class WalletLogin {
|
||||||
|
get signInLabel() {
|
||||||
|
return $("[data-testid='sign-in']");
|
||||||
|
}
|
||||||
|
get mnemonic() {
|
||||||
|
return $("#mnemonic");
|
||||||
|
}
|
||||||
|
get signInButton() {
|
||||||
|
return $("[type='submit']");
|
||||||
|
}
|
||||||
|
get errorValidation() {
|
||||||
|
return $("[class='MuiAlert-message']");
|
||||||
|
}
|
||||||
|
get accountBalance() {
|
||||||
|
return $("[data-test-id='account-balance']");
|
||||||
|
}
|
||||||
|
get accountBalanceText() {
|
||||||
|
return $("[class='MuiAlert-message']");
|
||||||
|
}
|
||||||
|
get walletAddress() {
|
||||||
|
return $("[data-testid='wallet-address']");
|
||||||
|
}
|
||||||
|
|
||||||
|
//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,37 @@
|
|||||||
|
class WalletReceive {
|
||||||
|
get receiveNymHeader() {
|
||||||
|
return $(
|
||||||
|
"#root > div > div:nth-child(2) > div:nth-child(2) > div > div > div > div.MuiCardHeader-root > div > span"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
get receiveNymText() {
|
||||||
|
return $("[data-testid='receive-nym']");
|
||||||
|
}
|
||||||
|
get walletAddress() {
|
||||||
|
return $("[data-testid='client-address']");
|
||||||
|
}
|
||||||
|
get copyButton() {
|
||||||
|
return $("[data-testid='copy-button']");
|
||||||
|
}
|
||||||
|
get qrCode() {
|
||||||
|
return $("[data-testid='qr-code']");
|
||||||
|
}
|
||||||
|
|
||||||
|
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,52 @@
|
|||||||
|
class WalletSend {
|
||||||
|
get fromAddress() {
|
||||||
|
return $("#from");
|
||||||
|
}
|
||||||
|
get toAddress() {
|
||||||
|
return $("#to");
|
||||||
|
}
|
||||||
|
get amount() {
|
||||||
|
return $("#amount");
|
||||||
|
}
|
||||||
|
get nextButton() {
|
||||||
|
return $("[data-testid='button");
|
||||||
|
}
|
||||||
|
get sendHeader() {
|
||||||
|
return $("[data-testid='Send punk']");
|
||||||
|
}
|
||||||
|
get accountBalance() {
|
||||||
|
return $("[data-testid='account-balance']");
|
||||||
|
}
|
||||||
|
get amountReviewAndSend() {
|
||||||
|
return $("[data-testid='Amount']");
|
||||||
|
}
|
||||||
|
get toAddressReviewAndSend() {
|
||||||
|
return $("[data-testid='To']");
|
||||||
|
}
|
||||||
|
get fromAddressReviewAndSend() {
|
||||||
|
return $("[data-testid='From']");
|
||||||
|
}
|
||||||
|
get transferFeeAmount() {
|
||||||
|
return $("[data-testid='Transfer fee']");
|
||||||
|
}
|
||||||
|
get reviewAndSendBackButton() {
|
||||||
|
return $("[data-testid='back-button']");
|
||||||
|
}
|
||||||
|
get sendButton() {
|
||||||
|
return $("[data-testid='button']");
|
||||||
|
}
|
||||||
|
get transactionComplete() {
|
||||||
|
return $("[data-testid='transaction-complete']");
|
||||||
|
}
|
||||||
|
get transactionCompleteRecipient() {
|
||||||
|
return $("[data-testid='to-address']");
|
||||||
|
}
|
||||||
|
get transactionCompleteAmount() {
|
||||||
|
return $("[data-testid='send-amount']");
|
||||||
|
}
|
||||||
|
get finishButton() {
|
||||||
|
return $("[data-testid='button']");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new WalletSend();
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
class WallentUndelegate {
|
||||||
|
get transactionFee() {
|
||||||
|
return $("[data-testid='fee-amount']");
|
||||||
|
}
|
||||||
|
get mixNodeRadioButton() {
|
||||||
|
return $("[value='mixnode']");
|
||||||
|
}
|
||||||
|
get gatewayRadionButton() {
|
||||||
|
return $("[value='gateway']");
|
||||||
|
}
|
||||||
|
get nodeIdentity() {
|
||||||
|
return $("#mui-55011");
|
||||||
|
}
|
||||||
|
get identityHelper() {
|
||||||
|
return $("#identity-helper-text");
|
||||||
|
}
|
||||||
|
get delegateButton() {
|
||||||
|
return $("[data-testid='submit-button']");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new WallentUndelegate();
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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 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(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.scrollIntoView(walletHomepage.unBondButton);
|
||||||
|
await helper.navigateAndClick(walletHomepage.unBondButton);
|
||||||
|
|
||||||
|
const getText = await bondPage.header.getText();
|
||||||
|
const unbondText = await bondPage.unBondWarning.getText();
|
||||||
|
|
||||||
|
await bondPage.unBondButton.isClickable();
|
||||||
|
//assert all field are not functional
|
||||||
|
expect(getText).toEqual(textConstants.unbondNodeHeaderText);
|
||||||
|
expect(unbondText).toEqual(textConstants.unbondMixNodeText);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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();
|
||||||
|
|
||||||
|
expect(getIdentityValidation).toEqual(
|
||||||
|
textConstants.nodeIdentityValidationText
|
||||||
|
);
|
||||||
|
expect(getAmountValidation).toEqual(textConstants.amountValidationText);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("input delegate amount to a mix node then broadcast the transaction then check account balances", async () => {
|
||||||
|
const balanceText = await delegatePage.accountBalance.getText();
|
||||||
|
|
||||||
|
const getTransfeeAmount = await delegatePage.transactionFeeAmount.getText();
|
||||||
|
|
||||||
|
await delegatePage.nodeIdentity.setValue(
|
||||||
|
userData.identity_key_to_delegate_mix_node
|
||||||
|
);
|
||||||
|
|
||||||
|
await delegatePage.amountToDelegate.setValue(userData.delegate_amount);
|
||||||
|
|
||||||
|
//transfer fee + amount delegation
|
||||||
|
const sumCost = await helper.calculateFees(
|
||||||
|
balanceText,
|
||||||
|
getTransfeeAmount,
|
||||||
|
userData.delegate_amount,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await delegatePage.delegateStakeButton.click();
|
||||||
|
|
||||||
|
await delegatePage.successfullyDelegate.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
|
||||||
|
|
||||||
|
await delegatePage.finishButton.click();
|
||||||
|
|
||||||
|
expect(await helper.currentBalance(availablePunk)).toEqual(sumCost);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("input amount to stake to a gateway then broadcast the transaction 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,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await delegatePage.delegateStakeButton.click();
|
||||||
|
|
||||||
|
await delegatePage.successfullyDelegate.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,45 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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("wallet splash screen", () => {
|
||||||
|
it("should have the sign in header present", 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
|
||||||
|
//trim the punk address
|
||||||
|
it("successfully input mnemonic and log in", async () => {
|
||||||
|
const mnemonic = await helper.decodeBase(userData.mnemonic);
|
||||||
|
|
||||||
|
await walletLogin.enterMnemonic(mnemonic);
|
||||||
|
|
||||||
|
await walletLogin.walletAddress.waitForEnabled({ timeout: 5000 });
|
||||||
|
|
||||||
|
const getWalletAddress = await walletLogin.walletAddress.getText();
|
||||||
|
//currently 35 characters are displayed along with three ...
|
||||||
|
//current hack we can assume this is the correct wallet
|
||||||
|
const walletTruncated = userData.punk_address.substring(0, 35);
|
||||||
|
|
||||||
|
expect(walletTruncated + "...").toContain(getWalletAddress);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("successfully log out the application", async () => {
|
||||||
|
await helper.scrollIntoView(homepPage.logOutButton);
|
||||||
|
|
||||||
|
await homepPage.logOutButton.click();
|
||||||
|
|
||||||
|
await walletLogin.signInLabel.waitForEnabled({ timeout: 1500 });
|
||||||
|
expect(await walletLogin.signInLabel.isDisplayed()).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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 helper.navigateAndClick(walletHomepage.receiveButton);
|
||||||
|
|
||||||
|
await receive.receiveNymHeader.waitForDisplayed({ timeout: 1500 });
|
||||||
|
|
||||||
|
await receive.WaitForButtonChangeOnCopy();
|
||||||
|
|
||||||
|
const textHeader = await receive.receiveNymHeader.getText();
|
||||||
|
const getInformationText = await receive.receiveNymText.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,55 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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 helper.navigateAndClick(walletHomepage.sendButton);
|
||||||
|
|
||||||
|
const textHeader = await sendWallet.sendHeader.getText();
|
||||||
|
|
||||||
|
expect(textHeader).toContain(textConstants.sendPunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("send funds correctly to another punk address", async () => {
|
||||||
|
//already logged in due to the previous test
|
||||||
|
const getCurrentBalance = await walletHomepage.accountBalance.getText();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
const transFee = await sendWallet.transferFeeAmount.getText();
|
||||||
|
|
||||||
|
await sendWallet.sendButton.click();
|
||||||
|
|
||||||
|
await sendWallet.finishButton.waitForClickable({ timeout: 10000 });
|
||||||
|
|
||||||
|
let sumCost = await helper.calculateFees(
|
||||||
|
getCurrentBalance,
|
||||||
|
transFee,
|
||||||
|
userData.amount_to_send,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
await walletHomepage.accountBalance.isDisplayed();
|
||||||
|
|
||||||
|
const availablePunk = await walletHomepage.accountBalance.getText();
|
||||||
|
|
||||||
|
await sendWallet.finishButton.click();
|
||||||
|
|
||||||
|
//expect new account balance - the fee calculation above
|
||||||
|
expect(await helper.currentBalance(availablePunk)).toEqual(sumCost);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
const userData = require("../../../common/data/user-data.json");
|
||||||
|
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 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: 1500 });
|
||||||
|
|
||||||
|
await unDelegatePage.unDelegateButton.isEnabled();
|
||||||
|
|
||||||
|
await unDelegatePage.unDelegateGatewayRadioButton.click();
|
||||||
|
|
||||||
|
await unDelegatePage.unDelegateGatewayRadioButton.isSelected();
|
||||||
|
|
||||||
|
const mixNodeRadioButton =
|
||||||
|
await unDelegatePage.unMixNodeRadioButton.isSelected();
|
||||||
|
expect(mixNodeRadioButton).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
const walletLogin = require("../../pages/wallet.login");
|
||||||
|
const walletSignUp = require("../../pages/wallet.create");
|
||||||
|
const textConstants = require("../../../common/constants/text-constants");
|
||||||
|
|
||||||
|
describe("non existing wallet holder", () => {
|
||||||
|
//wallet mnemonic gets pushed here
|
||||||
|
const DATA = [];
|
||||||
|
it("create a new account and wallet", async () => {
|
||||||
|
const signInText = await walletLogin.signInLabel.getText();
|
||||||
|
expect(signInText).toEqual(textConstants.homePageSignIn);
|
||||||
|
|
||||||
|
await walletSignUp.createAccount.click();
|
||||||
|
|
||||||
|
//wallet generation takes some time - apply wait
|
||||||
|
await walletSignUp.create.click();
|
||||||
|
|
||||||
|
await walletSignUp.accountCreatedSuccessfully.waitForEnabled({
|
||||||
|
timeout: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const getWalletText = await walletSignUp.punkAddress.getText();
|
||||||
|
expect(getWalletText.length).toEqual(43);
|
||||||
|
|
||||||
|
const accountCreated =
|
||||||
|
await walletSignUp.accountCreatedSuccessfully.getText();
|
||||||
|
expect(accountCreated).toEqual(textConstants.walletSuccess);
|
||||||
|
|
||||||
|
const getMnemonic = await walletSignUp.walletMnemonicValue.getText();
|
||||||
|
DATA.push(getMnemonic);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigate back to sign in screen and validate mnemonic works", async () => {
|
||||||
|
await walletSignUp.backToSignIn.click();
|
||||||
|
|
||||||
|
await walletLogin.enterMnemonic(DATA[0]);
|
||||||
|
|
||||||
|
await walletLogin.walletAddress.isDisplayed();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
const os = require("os");
|
||||||
|
const path = require("path");
|
||||||
|
const { spawn, spawnSync } = require("child_process");
|
||||||
|
//insert path to binary
|
||||||
|
const nym_path = "../target/release/nym-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: {
|
||||||
|
home: ["./tests/specs/existinguser/test.wallet.home.js"],
|
||||||
|
sendreceive: [
|
||||||
|
"./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",
|
||||||
|
],
|
||||||
|
newuser: ["./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
|
||||||
|
bail: 0,
|
||||||
|
framework: "mocha",
|
||||||
|
reporters: ["spec"],
|
||||||
|
mochaOpts: {
|
||||||
|
ui: "bdd",
|
||||||
|
timeout: 60000,
|
||||||
|
},
|
||||||
|
logLevel: "silent",
|
||||||
|
|
||||||
|
// ===================
|
||||||
|
// Test Reporters
|
||||||
|
// ===================
|
||||||
|
reporters: [
|
||||||
|
[
|
||||||
|
"allure",
|
||||||
|
{
|
||||||
|
outputDir: "allure-results",
|
||||||
|
disableWebdriverStepsReporting: true,
|
||||||
|
disableWebdriverScreenshotsReporting: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
// 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] }
|
||||||
|
)),
|
||||||
|
|
||||||
|
afterTest: function (
|
||||||
|
test,
|
||||||
|
context,
|
||||||
|
{ error, result, duration, passed, retries }
|
||||||
|
) {
|
||||||
|
if (error) {
|
||||||
|
browser.takeScreenshot();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// clean up the `tauri-driver` process we spawned at the start of the session
|
||||||
|
afterSession: () => tauriDriver.kill(),
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -9,30 +9,66 @@ RELEASE_DIRECTORY="target/release"
|
|||||||
VERSION_NUMBER=$1
|
VERSION_NUMBER=$1
|
||||||
WALLET_ADDRESS_CONST=n1435n84se65tn7yv536am0sfvng4yyrwj7thhxr
|
WALLET_ADDRESS_CONST=n1435n84se65tn7yv536am0sfvng4yyrwj7thhxr
|
||||||
MOCK_HOST="1.2.3.4"
|
MOCK_HOST="1.2.3.4"
|
||||||
OUTPUT=$(for i in {1..8}; do echo -n $(( $RANDOM % 10 )); done)
|
OUTPUT=$(for i in {1..8}; do echo -n $(($RANDOM % 10)); done)
|
||||||
ID="test-${OUTPUT}"
|
ID="test-${OUTPUT}"
|
||||||
|
BINARY_NAME="nym-gateway"
|
||||||
|
|
||||||
echo "the version number is ${VERSION_NUMBER}"
|
echo "the version number is ${VERSION_NUMBER} to be installed from github"
|
||||||
|
|
||||||
cd ${PWD}${RELEASE_DIRECTORY}
|
cd ${PWD}${RELEASE_DIRECTORY}
|
||||||
|
|
||||||
if [ -f nym-gateway ]; then
|
# steps
|
||||||
|
# we curl the existing binary from the release page of github
|
||||||
|
# we init the binary to check successful init
|
||||||
|
# then in our testing branch, we build the binary locally
|
||||||
|
# re run the init based upon the configuration injected
|
||||||
|
# we validate that no errors are return from upgrading the binary against the test
|
||||||
|
|
||||||
|
# install the current release binary
|
||||||
|
# so this is dependant on running on a linux machine for the time being
|
||||||
|
|
||||||
|
curl -L https://github.com/nymtech/nym/releases/download/nym-binaries-${RELEASE_VERSION_NUMBER}/$BINARY_NAME -o $BINARY_NAME
|
||||||
|
chmod u+x $BINARY_NAME
|
||||||
|
|
||||||
|
#--------------------------------------
|
||||||
|
# functions
|
||||||
|
#--------------------------------------
|
||||||
|
|
||||||
|
check_gateway_binary_build() if [ -f nym-gateway ]; then
|
||||||
echo "running init tests"
|
echo "running init tests"
|
||||||
# we wont use config env files for now
|
# we wont use config env files for now
|
||||||
# unless we want to use a specific environment
|
# unless we want to use a specific environment
|
||||||
OUTPUT=$(./nym-gateway --output json init --id ${ID} --host ${MOCK_HOST} --wallet-address ${WALLET_ADDRESS_CONST}) > /dev/null 2>&1
|
OUTPUT=$(./nym-gateway --output json init --id ${ID} --host ${MOCK_HOST} --wallet-address ${WALLET_ADDRESS_CONST}) >/dev/null 2>&1
|
||||||
|
|
||||||
# get jq values for things we can assert against
|
# get jq values for things we can assert against
|
||||||
VALUE=$(echo ${OUTPUT} | jq .wallet_address)
|
VALUE=$(echo ${OUTPUT} | jq .wallet_address)
|
||||||
VALUE=${VALUE#\"}
|
VALUE=${VALUE#\"}
|
||||||
VALUE=${VALUE%\"}
|
VALUE=${VALUE%\"}
|
||||||
|
|
||||||
|
echo $OUTPUT
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# do asserts here based upon the output on init
|
# do asserts here based upon the output on init
|
||||||
|
|
||||||
assert $(cat ${VALUE}) $(echo ${WALLET_ADDRESS_CONST})
|
assert $(echo ${VALUE}) $(echo ${WALLET_ADDRESS_CONST})
|
||||||
assert_end nym-gateway-tests
|
assert_end nym-gateway-tests
|
||||||
else
|
else
|
||||||
echo "exting test no binary found"
|
echo "exting test no binary found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# we run the release version first
|
||||||
|
check_gateway_binary_build
|
||||||
|
# lets remove the binary then navigate to the target/release directory for checking the latest version
|
||||||
|
# expect to have successful output and configuration
|
||||||
|
|
||||||
|
if [ -f $BINARY_NAME ]; then
|
||||||
|
echo "removing nym-mixnode"
|
||||||
|
rm -rf $BINARY_NAME
|
||||||
|
else
|
||||||
|
echo "no binary found exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# we should expect it to pass because no errors should be presented when performing the upgrade of an init
|
||||||
|
# this should be caught at testing staage
|
||||||
|
check_gateway_binary_build
|
||||||
|
|||||||
@@ -4,31 +4,86 @@
|
|||||||
|
|
||||||
PWD="../"
|
PWD="../"
|
||||||
RELEASE_DIRECTORY="target/release"
|
RELEASE_DIRECTORY="target/release"
|
||||||
VERSION_NUMBER=$1
|
RELEASE_VERSION_NUMBER=$1
|
||||||
WALLET_ADDRESS_CONST=n1435n84se65tn7yv536am0sfvng4yyrwj7thhxr
|
WALLET_ADDRESS_CONST=n1435n84se65tn7yv536am0sfvng4yyrwj7thhxr
|
||||||
MOCK_HOST="1.2.3.4"
|
MOCK_HOST="1.2.3.4"
|
||||||
OUTPUT=$(for i in {1..8}; do echo -n $(( $RANDOM % 10 )); done)
|
OUTPUT=$(for i in {1..8}; do echo -n $(($RANDOM % 10)); done)
|
||||||
ID="test-${OUTPUT}"
|
ID="test-${OUTPUT}"
|
||||||
|
BINARY_NAME="nym-mixnode"
|
||||||
|
|
||||||
echo "the version number is ${VERSION_NUMBER}"
|
echo "the version number is ${VERSION_NUMBER} to be installed from github"
|
||||||
|
|
||||||
cd $PWD/$RELEASE_DIRECTORY
|
# steps
|
||||||
|
# we curl the existing binary from the release page of github
|
||||||
|
# we init the binary to check successful init
|
||||||
|
# then in our testing branch, we build the binary locally
|
||||||
|
# re run the init based upon the configuration injected
|
||||||
|
# we validate that no errors are return from upgrading the binary against the test
|
||||||
|
|
||||||
if [ -f nym-mixnode ]; then
|
# install the current release binary
|
||||||
echo "running init tests"
|
# so this is dependant on running on a linux machine for the time being
|
||||||
# we wont use config env files for now
|
curl -L "https://github.com/nymtech/nym/releases/download/nym-binaries-${RELEASE_VERSION_NUMBER}/${BINARY_NAME}" -o nym-mixnode
|
||||||
OUTPUT=$(./nym-mixnode --output json init --id ${ID} --host ${MOCK_HOST} --wallet-address ${WALLET_ADDRESS_CONST}) > /dev/null 2>&1
|
chmod u+x "$BINARY_NAME"
|
||||||
|
|
||||||
# get jq values for things we can assert against
|
|
||||||
# tidy this bit up - okay for first push
|
|
||||||
VALUE=$(echo ${OUTPUT} | jq .wallet_address)
|
|
||||||
VALUE=${VALUE#\"}
|
|
||||||
VALUE=${VALUE%\"}
|
|
||||||
|
|
||||||
# do asserts here based upon the output on init
|
|
||||||
|
|
||||||
assert $(cat ${VALUE}) $(echo ${WALLET_ADDRESS_CONST})
|
#--------------------------------------
|
||||||
assert_end nym-mixnode-tests
|
# functions
|
||||||
|
#--------------------------------------
|
||||||
|
check_mixnode_binary_build() {
|
||||||
|
if [ -f "$BINARY_NAME" ]; then
|
||||||
|
echo "running init tests"
|
||||||
|
# we wont use config env files for now
|
||||||
|
OUTPUT=$(./${BINARY_NAME} --output json init --id ${ID} --host ${MOCK_HOST} --wallet-address ${WALLET_ADDRESS_CONST} > /dev/null)
|
||||||
|
# get jq values for things we can assert against
|
||||||
|
# tidy this bit up - okay for first push
|
||||||
|
|
||||||
|
VALUE="$(echo ${OUTPUT} | jq .wallet_address | tr -d '"')"
|
||||||
|
|
||||||
|
# do asserts here based upon the output on init
|
||||||
|
assert "echo ${VALUE}" $(echo ${WALLET_ADDRESS_CONST})
|
||||||
|
assert_end nym-mixnode-tests
|
||||||
|
else
|
||||||
|
echo "exiting test no binary found"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------
|
||||||
|
# tests
|
||||||
|
#-------------------------------
|
||||||
|
|
||||||
|
# we run the release version first
|
||||||
|
check_mixnode_binary_build
|
||||||
|
# whoami
|
||||||
|
# this is dependant on where it runs on ci potentially, will need to tweak this in the future
|
||||||
|
first_init=$(cat /root/.nym/mixnodes/${ID}/config/config.toml | grep -v "^\[mixnode\]$" | grep -v "^version =")
|
||||||
|
|
||||||
|
#lets remove the binary then navigate to the target/release directory for checking the latest version
|
||||||
|
if [ -f "$BINARY_NAME" ]; then
|
||||||
|
echo "removing nym-mixnode"
|
||||||
|
rm -rf "$BINARY_NAME"
|
||||||
|
echo "successfully removed nym-mixnode"
|
||||||
else
|
else
|
||||||
echo "exting test no binary found"
|
echo "no binary found exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# we should expect it to pass because no errors should be presented when performing the upgrade of an init
|
||||||
|
# this should be caught at testing stage
|
||||||
|
# navigate to latest binary build
|
||||||
|
cd $PWD$RELEASE_DIRECTORY
|
||||||
|
#re run against the current binary built locally
|
||||||
|
check_mixnode_binary_build
|
||||||
|
|
||||||
|
echo "diff the config files after each init"
|
||||||
|
echo "-------------------------------------"
|
||||||
|
|
||||||
|
second_init=$(cat /root/.nym/mixnodes/${ID}/config/config.toml | grep -v "^\[mixnode\]$" | grep -v "^version =")
|
||||||
|
|
||||||
|
diff -w <(echo "$first_init") <(echo "$second_init")
|
||||||
|
|
||||||
|
# check the status of the diff
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "no differences in config files, exiting script"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "there are differences in the config files, it may require a fresh init on the binary"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
@@ -10855,9 +10855,9 @@ htmlparser2@^6.1.0:
|
|||||||
entities "^2.0.0"
|
entities "^2.0.0"
|
||||||
|
|
||||||
http-cache-semantics@^4.1.0:
|
http-cache-semantics@^4.1.0:
|
||||||
version "4.1.1"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
|
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
|
||||||
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
|
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
|
||||||
|
|
||||||
http-deceiver@^1.2.7:
|
http-deceiver@^1.2.7:
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
|
|||||||
Reference in New Issue
Block a user