Adding more tests

This commit is contained in:
Benedetta
2022-07-25 08:39:07 +02:00
parent edcaf72714
commit bbaa06417d
71 changed files with 565 additions and 1391 deletions
+5 -5
View File
@@ -51,12 +51,12 @@ jobs:
- name: Install dependencies
run: yarn install
working-directory: nym-wallet/webdriver
working-directory: nym-wallet/wallet-ui-tests
- name: Remove existing user datafile
uses: JesseTG/rm@v1.0.2
with:
path: nym-wallet/webdriver/common/data/user-data.json
path: nym-wallet/wallet-ui-tests/common/user-data.json
- name: Create user data json file
id: create-json
@@ -64,7 +64,7 @@ jobs:
with:
name: "user-data.json"
json: ${{ secrets.WALLET_USERDATA }}
dir: "nym-wallet/webdriver/common/data/"
dir: "nym-wallet/wallet-ui-tests/common/"
- name: Install tauri-driver
uses: actions-rs/cargo@v1
@@ -73,5 +73,5 @@ jobs:
args: tauri-driver
- name: Launch tests
run: xvfb-run yarn test:runall
working-directory: nym-wallet/webdriver
run: xvfb-run yarn test
working-directory: nym-wallet/wallet-ui-tests
@@ -1,13 +0,0 @@
{
"version": 1,
"accounts": [
{
"id": "default",
"account": {
"ciphertext": "cq5w4W5ex5eFFRcqLG+824XyUAUoYmrRY3NGw/rue6/mLoQKQE/07+BxzRuKjyYFasC1HBPg41KJwp2IY+/7+80rB9aXPpaKVLUcG9U40qgCw66WhgxTrXOnrt5toefpSTBL7f9N/PVwpuumfAgD9CS0ioB7/9Qoea7nYKkextGX15ex26B/ndQddvUkQ4gx+Vq7OLymv4l+nkdZ2nKMja349zd/BjnzPBB68/iIjyYlivVjtQ7FRbvpNRj6Mjg4905wGlO7bTpkw+RGiaGK4pK8fTWz8gAKr8GYoXPD",
"salt": "SPVGdbVyoEayD4ZzM4I+Jg==",
"iv": "tjpn/tRjD1gty+fQ"
}
}
]
}
@@ -1,13 +0,0 @@
{
"version": 1,
"accounts": [
{
"id": "default",
"account": {
"ciphertext": "3MDgoU2i5QMc9r80yPeq2AMk5wpkke0tXum5NsOE5NcFciF+aHLQW0dvXbGszap1y3nN4+YZD3cgGrmtKh/cChqRGJDkniaxdf3XPHh9RkiWXw2KSHHeyGrFY0INJeiky1ZtUFhWhopcHJWSnfCmVC15YFpnM5xOKpITjHAFhGt98MaYR+mS+3zoUFrjYbaZRh2TR2lFWsbR8YU1uaTYqJZ1HX1PBCub6aS3vjQm0Fwa+hAtR/gMymXJc5qtruTO4NbqYtMj3Z9eIgoVB+56SLAXlIF1Uo1pjvV0mx1hWNNiIc10ujF/wl/nnKF6icOcmrfm9XhOtsvUYBsE/wAIJZw3LKXgSX+hJbOl+zLAwJZK1xiL8n/nM1IJZDn+Wu6z0OzRaj9S7T16+brMw1oaqjk56saM8n5z725fizJj+ur6gnPBWnoyHPaCHgHdB2PKQNY0ZlwRM6dVncRaEWQDLAboyMq3FXxK9UbusNcDFpYw6bdnuJlNVf6y9yxwyvkUrt5YtgfkLyoW42z1PVtVWsV9P8eE/A/tnYjXf34xvba3K8Y1/3DTi7uuydNrSR/XhA+pevz68VWCbY+j746Yi8Lz7altePphkjfJAezodobKvMplXzqInopIWNovyemw/+1E7WZbkQIOAXg1WC1+Y/df+dffRGuGRdDerfRLmA5XLej1M/wE3WQ7b9KwlAo6XJ4hnQKwyDCqYP/ButBXW1AOnnZpCq59gGbiccZJsTMZB4OP95yFPgz8//IeDgma2PDixVmDEp0SGHhN7dlSoNa5eoglblqzJu/TcTA6jmQFA3ef0GiA3QzBjmyB4bz0bFybh8XA1brVIVlsjRwXb3/UYaVqsP6Hy1QDUpZofXIJs5lK0hUd0ECdaNFXXgHd25ifPocp09WLFyK92H6i3ABDZ7pu3b4lTUt6kHt6LTVsKkyylmYf2iMHnCcmfy4uxGTXxRjPjMgKL8pd++OZ3q62jLBuoTjgdj6pccwDvD+NYQ2FFeHmBzxyTLqUyKltYiyFlJHWLKOcXyeDHzRhHic+e/wn3VhM3NdrvtqYWA9m72Ye1L1I7VX7KatGurG6CeiFiY5xHxxpLT7dF0fJ7uxRye4JnRyYQuU7iK72qCKjgYjwjCIha4qPi5Q/x6S+uVe7yX5Eb73L3eB+IlkyW9wPHmSOcE4GpbMU96tK8xoxT0T9eQlj050GDnJ/oI2XHfZTs1bIxsjfZqW03g==",
"salt": "wXR3RnPmsoA3ncrixIvaUw==",
"iv": "/Zjn1OXsLJhA43n/"
}
}
]
}
@@ -1,21 +0,0 @@
{
"version": 1,
"accounts": [
{
"id": "first",
"account": {
"ciphertext": "icnpxLmr/H7FIIOaEf7DYNLuM6uhh7poEppXpYCllQD33TjY+8eLtVvhEQmjX60IQeFOd+1JCcrHa2B12vlBAYlfM4gBxA6d2ZJ8+Dw/vNvBNyChiyUx2euV3vPGOs22r/XDBsmEeF40XZcXftQZa2kzYaPnkbP+eiMOIWkcY4FYOEHwx5SxT4VBPZIrVTC3iDalJLWybVbbw/Bc2zbzEXI1ckg4Ccydj95SMil9BiyDpALfZqwlai7I97S+BjmcVxSCsYqFjTkRUHVMjrEr7fWHKU4DIOM=",
"salt": "CtnbfkxTybqz0U4cPHW2jQ==",
"iv": "77ZROU6dAMttEWwS"
}
},
{
"id": "second",
"account": {
"ciphertext": "nsqZHdQFlskglc5izKgnr8sBwdMmd82h2Rnjdos9EUca3cqkUdFYEjZDsK8OGR3GZ9alLTNt/1U97Rvvr2HPAWbzl23FW2YXaLTA6yj6ZwQK5w0MYE061NYbcxNHuzT9f5aQWkGULAk4RWb5t8eUX7y/NdJr3tA5xuGOLhooTfBB98/4RpupDsYGZp1DPC/GMFppOA3GmKs9bacZm805Bhfq5mwhXab1SjJQpFHMHisCMhxo/oLqulKML1tQMetBdqDTjJmPpdUnd1mi",
"salt": "J2TMLjKv4dkZ/kXso9FGhg==",
"iv": "CTqqoMa4LetvBKCP"
}
}
]
}
+2 -2
View File
@@ -28,7 +28,7 @@ type ClientAddressProps = {
showEntireAddress?: boolean;
};
export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string }> = ({
export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string } > = ({
withLabel,
withCopy,
showEntireAddress,
@@ -44,7 +44,7 @@ export const ClientAddressDisplay: FC<ClientAddressProps & { address?: string }>
)}
<AddressTooltip address={address} visible={!showEntireAddress}>
<Typography variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
<Typography data-testid="accountNumber" variant="body2" component="span" sx={{ mr: 1, color: 'text.primary', fontWeight: 400 }}>
{showEntireAddress ? address || '' : splice(6, address)}
</Typography>
</AddressTooltip>
@@ -30,6 +30,7 @@ export const CopyToClipboard = ({ text = '', iconButton }: { text?: string; icon
return (
<Tooltip title={!copied ? 'Copy' : 'Copied!'} leaveDelay={500}>
<IconButton
data-testid="copyy"
onClick={() => handleCopy(text)}
size="small"
sx={{
@@ -41,7 +41,7 @@ export const SimpleModal: React.FC<{
<Box sx={{ ...modalStyle, ...sx }}>
{displayErrorIcon && <ErrorOutline color="error" sx={{ mb: 3 }} />}
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography fontSize={20} fontWeight={600} sx={{ color: 'text.primary', ...headerStyles }}>
<Typography fontSize={20} fontWeight={600} sx={{ color: 'text.primary', ...headerStyles }} data-header-testid={header}>
{header}
</Typography>
{!hideCloseIcon && <CloseIcon onClick={onClose} cursor="pointer" />}
+1 -1
View File
@@ -87,7 +87,7 @@ export const Nav = () => {
}
})
.map(({ Icon, onClick, label, route }) => (
<ListItem disableGutters key={label} onClick={onClick} sx={{ cursor: 'pointer' }}>
<ListItem disableGutters key={label} onClick={onClick} sx={{ cursor: 'pointer' }} data-testid={label}>
<ListItemIcon
sx={{
minWidth: 30,
@@ -7,8 +7,8 @@ import { config } from '../config';
const networks: { networkName: Network; name: string }[] = [
{ networkName: 'MAINNET', name: 'Nym Mainnet' },
{ networkName: 'SANDBOX', name: 'Testnet Sandbox'},
{ networkName: 'QA', name: 'QA' },
{ networkName: 'SANDBOX', name: 'Testnet Sandbox' },
{ networkName: 'QA', name: 'QA' },
];
const NetworkItem: React.FC<{ title: string; isSelected: boolean; onSelect: () => void }> = ({
@@ -16,7 +16,7 @@ const NetworkItem: React.FC<{ title: string; isSelected: boolean; onSelect: () =
isSelected,
onSelect,
}) => (
<ListItem button onClick={onSelect} data-testid={ title }>
<ListItem button onClick={onSelect} data-testid={title}>
<ListItemIcon>{isSelected && <CheckSharp color="success" />}</ListItemIcon>
<ListItemText>{title}</ListItemText>
</ListItem>
@@ -38,6 +38,7 @@ export const NetworkSelector = () => {
return (
<>
<Button
data-testid="networkEnv"
variant="text"
color="primary"
sx={{ color: 'text.primary' }}
+1 -1
View File
@@ -31,7 +31,7 @@ export const NymCard: React.FC<{
{noPadding ? (
<CardContentNoPadding>{children}</CardContentNoPadding>
) : (
<CardContent sx={{ p: 3 }} data-testid="check-balance">{children}</CardContent>
<CardContent sx={{ p: 3 }} >{children}</CardContent>
)}
</Card>
);
+4 -1
View File
@@ -15,7 +15,7 @@ export const MnemonicInput: React.FC<{
label="Mnemonic"
inputProps={{
"data-testid": "mnemonicInput",
}}
}}
type={showPassword ? 'input' : 'password'}
value={mnemonic}
onChange={(e) => onUpdateMnemonic(e.target.value)}
@@ -66,6 +66,9 @@ export const PasswordInput: React.FC<{
</IconButton>
),
}}
inputProps={{
"data-testid": label,
}}
/>
</Box>
{error && <Error message={error} />}
@@ -54,9 +54,7 @@ export const WordTiles = ({
<Grid container spacing={3} justifyContent="center">
{mnemonicWords.map(({ name, index, disabled }) => (
<Grid
// data-testid="mnemonicWord"
data-testid={name}
item xs={2} key={index} onClick={() => onClick?.({ name, index })}>
item xs={2} key={index} onClick={() => onClick?.({ name, index })} data-testid="mnemonicWordTile">
<WordTile
mnemonicWord={name}
index={showIndex ? index : undefined}
@@ -82,7 +80,7 @@ const HiddenWord = ({ mnemonicWord }: { mnemonicWord: THiddenMnemonicWord }) =>
</Box>
</Fade>
</Box>
<Typography data-testid="number">{mnemonicWord.index}.</Typography>
<Typography data-testid="wordIndex">{mnemonicWord.index}.</Typography>
</Stack>
);
@@ -20,6 +20,7 @@ export const ConfirmMnemonic = () => {
<Subtitle subtitle="Enter the mnemonic you wish to create a password for" />
<MnemonicInput mnemonic={localMnemonic} onUpdateMnemonic={(mnc) => setLocalMnemonic(mnc)} error={error} />
<Button
data-testid="nextToPasswordCreation"
size="large"
variant="contained"
fullWidth
@@ -37,6 +38,7 @@ export const ConfirmMnemonic = () => {
Next
</Button>
<Button
data-testid="backToMnemonicSignIn"
size="large"
color="inherit"
fullWidth
@@ -57,6 +57,7 @@ export const ConnectPassword = () => {
label="Confirm password"
/>
<Button
data-testid="createPasswordButton"
size="large"
variant="contained"
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
@@ -65,6 +66,7 @@ export const ConnectPassword = () => {
{isLoading ? <CircularProgress size={25} /> : 'Create password'}
</Button>
<Button
data-testid="backToStep1PasswordCreation"
size="large"
color="inherit"
onClick={() => {
@@ -47,7 +47,6 @@ export const CreatePassword = () => {
onUpdatePassword={(pswd) => setPassword(pswd)}
label="Password"
autoFocus
data-testid="password"
/>
<PasswordStrength password={password} onChange={(isStrong) => setIsStrongPassword(isStrong)} />
</>
@@ -55,7 +54,6 @@ export const CreatePassword = () => {
password={confirmedPassword}
onUpdatePassword={(pswd) => setConfirmedPassword(pswd)}
label="Confirm password"
data-testid="confirmPassword"
/>
<Button
size="large"
@@ -39,7 +39,7 @@ export const SignInMnemonic = () => {
>
<Stack spacing={2}>
<MnemonicInput mnemonic={mnemonic} onUpdateMnemonic={(mnc) => setMnemonic(mnc)} error={error} />
<Button variant="contained" size="large" fullWidth type="submit" data-testid="signIn">
<Button variant="contained" size="large" fullWidth type="submit" data-testid="signInSubmitButton">
Sign in with mnemonic
</Button>
<Box display="flex" justifyContent={passwordExists ? 'center' : 'space-between'}>
@@ -47,7 +47,7 @@ export const SignInMnemonic = () => {
Back
</Button>
{!passwordExists && (
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')} data-testid="createPassword">
<Button color="info" onClick={() => handlePageChange('/confirm-mnemonic')} data-testid="goToCreatePassword">
Create a password
</Button>
)}
@@ -29,6 +29,7 @@ export const SignInPassword = () => {
autoFocus
/>
<Button
data-testid="signInPasswordButton"
variant="contained"
size="large"
fullWidth
@@ -38,6 +39,7 @@ export const SignInPassword = () => {
</Button>
<Box display="flex" justifyContent="space-between">
<Button
data-testid="backToSignInOptionsFromPassword"
color="inherit"
disableElevation
onClick={() => {
@@ -49,6 +51,7 @@ export const SignInPassword = () => {
</Button>
<Button
data-testid="forgotPasswordButton"
color="info"
onClick={() => {
setError(undefined);
@@ -45,15 +45,14 @@ export const VerifyMnemonic = () => {
<Subtitle subtitle="Select the words from your mnmonic based on their order" />
<HiddenWords mnemonicWords={hiddenRandomWords} />
<WordTiles
data-testid="number"
mnemonicWords={randomWords}
onClick={currentSelection !== numberOfRandomWords ? revealWord : undefined}
buttons
/>
<Stack spacing={3} sx={{ width: 300 }} data-testid="randomMnemonicWords">
<Stack spacing={3} sx={{ width: 300 }}>
<Button
variant="contained"
data-testid="next"
data-testid="nextToStep3"
fullWidth
size="large"
disabled={currentSelection !== numberOfRandomWords}
+1 -1
View File
@@ -99,7 +99,7 @@ const TerminalInner: React.FC = () => {
<Box width="100%" display="flex" justifyContent="space-between">
<Box display="flex" alignItems="center">
<TerminalIcon sx={{ mr: 1 }} />
<Typography mr={4}>Terminal</Typography>
<Typography mr={4} data-testid='terminal-header'>Terminal</Typography>
{!isBusy && <RefreshIcon onClick={refresh} cursor="pointer" />}
</Box>
<CloseIcon onClick={handleShowTerminal} cursor="pointer" />
+1 -1
View File
@@ -19,5 +19,5 @@
"@assets/*": ["../assets/*"]
}
},
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target", "webdriver", "wallet-ui-tests"]
"exclude": ["node_modules", "dist", "jest.config.js", "webpack.config.js", "webpack.prod.js", "webpack.common.js", "target", "wallet-ui-tests"]
}
@@ -0,0 +1,18 @@
class Helpers {
//helper to decode mnemonic so plain 24 character passphrase isn't in sight albeit it is presented when ruunning the scripts
// TO=-DO weork on this, figure out what's going on with the decoding bit
decodeBase = async (input) => {
var m = Buffer.from(input, "base64").toString();
return m;
};
navigateAndClick = async (element) => {
await element.click();
};
scrollIntoView = async (element) => {
await element.scrollIntoView();
};
}
module.exports = new Helpers();
@@ -0,0 +1,27 @@
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",
//homePage
qaNetwork: "QA",
sandboxNetwork: "Testnet Sandbox",
mainnetNetwork: "Nym Mainnet",
noNym: "0 NYM",
// user incorrect data
incorrectMnemonic: "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else heat",
randomString:"thisrandomstring",
password:"iAmThePassword1!",
incorrectPassword:"123notvalid",
};
@@ -1,5 +1,5 @@
{
"mnemonic": "value",
"mnemonic": "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else typical",
"punk_address": "",
"receiver_address": "",
"amount_to_send": "",
+4 -2
View File
@@ -4,9 +4,10 @@
"description": "ui tests for the nym wallet",
"scripts": {
"test": "wdio run wdio.conf.ts",
"test:welcome": "wdio run wdio.conf.ts --suite welcome",
"test:signup": "wdio run wdio.conf.ts --suite signup",
"test:login": "wdio run wdio.conf.ts --suite login",
"test:balance": "wdio run wdio.conf.ts --suite balance"
"test:balance": "wdio run wdio.conf.ts --suite balance",
"test:nav": "wdio run wdio.conf.ts --suite nav"
},
"author": "",
@@ -15,6 +16,7 @@
"-": "^0.0.1",
"@wdio/cli": "^7.16.16",
"save-dev": "^0.0.1-security",
"@zxing/browser": "^0.0.9",
"ts-node": "^10.6.0"
},
"devDependencies": {
@@ -0,0 +1,9 @@
const { exec } = require("child_process")
const deleteSavedFile = exec("rm '/home/benedetta/.local/share/nym-wallet/saved-wallet.json'", (err, stdout, stderr) => {
if (err) {
console.error(`${err.message}`)
return
} else
console.log("File deleted")
})
@@ -0,0 +1,3 @@
const { exec } = require("child_process")
const doesFileExist = exec("test -f /home/benedetta/.local/share/nym-wallet/saved-wallet.json")
@@ -0,0 +1,22 @@
class Nav {
get lightMode() { return $("[data-testid='LightModeOutlinedIcon']") }
get darkMode() { return $("[data-testid='ModeNightOutlinedIcon']") }
get terminalTitle() { return $("[data-testid='terminal-header']") }
get terminalIcon() { return $("[data-testid='TerminalIcon']") }
get balance() { return $("[data-testid='Balance']") }
get send() { return $("[data-testid='Send']") }
get receive() { return $("[data-testid='Receive']") }
get bond() { return $("[data-testid='Bond']") }
get unbond() { return $("[data-testid='Unbond']") }
get delegation() { return $("[data-testid='Delegation']") }
get closeIcon() { return $("[data-testid='CloseIcon']") }
}
export default new Nav()
@@ -1,45 +1,72 @@
import Balance from '../pageobjects/balanceScreen'
class Welcome {
//Welcome landing page
get signInButton() { return $("[data-testid='signIn']") }
get createAccount() { return $("[data-testid='createAccount']") }
//Welcome landing page
get signInButton() { return $("[data-testid='signIn']") }
get createAccount() { return $("[data-testid='createAccount']") }
// Existing account sign in option page
get signInMnemonic() { return $("[data-testid='signInWithMnemonic']") }
get signInPassword() { return $("[data-testid='signInWithPassword']") }
get backToWelcomePage() { return $("[data-testid='backToWelcomePage']") }
get forgotPassword() { return $("[data-testid='forgotPassword']") }
// Existing account sign in option page
get signInMnemonic() { return $("[data-testid='signInWithMnemonic']") }
get signInPassword() { return $("[data-testid='signInWithPassword']") }
get backToWelcomePage() { return $("[data-testid='backToWelcomePage']") }
get forgotPassword() { return $("[data-testid='forgotPassword']") }
// Sign in with mnemonic page
get mnemonicInput() { return $("[data-testid='mnemonicInput']") }
get signIn() { return $("[data-testid='signIn']") }
get backToSignInOptions() { return $("[data-testid='backToSignInOptions']") }
get createPassword() { return $("[data-testid='createPassword']") }
// Sign in with mnemonic page
get mnemonicInput() { return $("[data-testid='mnemonicInput']") }
get signIn() { return $("[data-testid='signInSubmitButton']") }
get backToSignInOptions() { return $("[data-testid='backToSignInOptions']") }
get createPassword() { return $("[data-testid='goToCreatePassword']") }
// Error
get error() { return $("[data-testid='error']") }
// Create password step 1/2
get backToMnemonicSignIn() { return $("[data-testid='backToMnemonicSignIn']") }
get nextToPasswordCreation() { return $("[data-testid='nextToPasswordCreation']") }
// Sign in with password
// Create password step 2/2
get password() { return $("[data-testid='Password']") }
get confirmPassword() { return $("[data-testid='Confirm password']") }
get createPasswordButton() { return $("[data-testid='createPasswordButton']") }
get backToStep1PasswordCreation() { return $("[data-testid='backToStep1PasswordCreation']") }
// Create account step 1/3
get copyMnemonic() { return $("[data-testid='copyMnemonic']") }
get iSavedMnemonic() { return $("[data-testid='iSavedMnemonic']") }
get mnemonicPhrase() { return $("[data-testid='mnemonicPhrase']") }
get backToWelcomePageFromCreate(){ return $("[data-testid='backToWelcome']")}
// Create account step 1/3
get copyMnemonic() { return $("[data-testid='copyMnemonic']") }
get iSavedMnemonic() { return $("[data-testid='iSavedMnemonic']") }
get mnemonicPhrase() { return $("[data-testid='mnemonicPhrase']") }
get backToWelcomePageFromCreate() { return $("[data-testid='backToWelcome']") }
// Create account step 2/3
get number() { return $("[data-testid='number']") }
get randomMnemonicWords() { return $("[data-testid='randomMnemonicWords']") }
//random words // random hidden words (top and bottom row, with name and index each)
get mnemonicWord() { return $("[data-testid='mnemonicWord']") }
// get randomMnemonicWords() { return $("#root > div > div > div > div:nth-child(6) > div:nth-child(1) > div > div") }
get next() { return $("[data-testid='next']") }
get backToStep1() { return $("[data-testid='backToStep1']") }
// Create account step 2/3
get wordIndex() { return $$("[data-testid='wordIndex']") }
get mnemonicWordTile() { return $$("[data-testid='mnemonicWordTile']") }
get nextToStep3() { return $("[data-testid='nextToStep3']") }
get backToStep1() { return $("[data-testid='backToStep1']") }
// Create account step 3/3
get password() { return $("[data-testid='password']") }
get confirmpassword() { return $("[data-testid='confirmpassword']") }
// get next() { return $("[data-testid='next']") }
get skipPasswordAndSignInWithMnemonic() { return $("[data-testid='skipPasswordAndSignInWithMnemonic']") }
// Create account step 3/3
get next() { return $("[data-testid='next']") } // TO-DO possibly rename this?
get skipPasswordAndSignInWithMnemonic() { return $("[data-testid='skipPasswordAndSignInWithMnemonic']") }
// Enter password to sign in
get enterPassword() { return $("[data-testid='Enter password']") }
get signInPasswordButton() { return $("[data-testid='signInPasswordButton']") }
get backToSignInOptionsFromPassword() { return $("[data-testid='backToSignInOptionsFromPassword']") }
get forgotPasswordButton() { return $("[data-testid='forgotPasswordButton']") }
// Errors
get error() { return $("[data-testid='error']") }
//TO-DO get this bit below working
getErrorMessage = async () => {
await (await this.error).waitForDisplayed({ timeout: 1500 })
await this.error.getText()
}
//login to the application
loginWithMnemonic = async (mnemonic) => {
await this.signInButton.click()
await this.signInMnemonic.click()
await this.mnemonicInput.waitForDisplayed()
await this.mnemonicInput.addValue(mnemonic);
await this.signIn.click();
await Balance.nymBalance.isExisting();
};
}
@@ -4,11 +4,14 @@ class Balance {
get checkBalance() { return $("[data-testid='check-balance']") }
get nymBalance() { return $("[data-testid='nym-balance']") }
// TO-DO figure out what's wrong with this copyAccountId locator being intercepted when clicked on
get copyAccountId() { return $("[data-testid='ContentCopyIcon']")}
get accountId() { return $("[data-testid='']")}
// get copyAccountId() { return $("[data-testid='copyy']")}
get accountNumber() { return $("[data-testid='accountNumber']")}
get networkDropdown() { return $("[data-testid='ArrowDropDownIcon']") }
get networkEnv() { return $("[data-testid='networkEnv']") }
get networkSelectQa() { return $("[data-testid='QA']") }
@@ -4,7 +4,6 @@ class Bond {
get mixnodeRadio() { return $("[data-testid='mix-node']") }
get gatewayRadio() { return $("[data-testid='gate-way']") }
get fundsAlert() { return $("[data-testid='fundsAlert']") }
get fundsAlert() { return $("[data-testid='fundsAlert']") }
}
@@ -0,0 +1,7 @@
class Delegation {
get delegationTitle() { return $("[data-testid='Delegation']") }
}
export default new Delegation()
@@ -0,0 +1,7 @@
class Receive {
get receiveNymTitle() { return $("[data-testid='Receive NYM']") }
}
export default new Receive()
@@ -0,0 +1,5 @@
class Send {
get sendHeader() { return $("[data-header-testid='Send']") } // TO-DO see if Send value can be used without changing the key name
}
export default new Send()
@@ -0,0 +1,7 @@
class Unbond {
get unbondTitle() { return $("[data-testid='Unbond']") }
}
export default new Unbond()
@@ -0,0 +1,37 @@
import Balance from '../../pageobjects/balanceScreen'
import Auth from '../../pageobjects/authScreens'
const textConstants = require("../../../common/text-constants");
const userData = require("../../../common/user-data.json");
describe('Balance screen displays correctly', () => {
it('selecting qa network', async () => {
//log in
await Auth.loginWithMnemonic(userData.mnemonic)
// select QA network
await (await Balance.networkDropdown).waitForDisplayed({ timeout: 4000 })
await (await Balance.networkDropdown).click()
await (await Balance.networkSelectQa).waitForDisplayed({ timeout: 2500 })
await (await Balance.networkSelectQa).click()
// verifty QA network has been selected properly
let network = await (await Balance.networkEnv).getText()
expect(network).toStrictEqual(textConstants.qaNetwork)
})
it('copy the account id', async () => {
// ensure the account number contains *something*
await (await Balance.accountNumber).waitForDisplayed({ timeout: 1500 })
let accountnumber = await (await Balance.accountNumber).getText()
expect(accountnumber[1]).toStrictEqual('1')
await (await Balance.copyAccountId).waitForDisplayed({ timeout: 1500 })
// TO-DO intercepted error when clicking copy,element exists though
await (await Balance.copyAccountId).click()
})
})
@@ -1,35 +0,0 @@
import Balance from '../../pageobjects/balanceScreen'
import Auth from '../../pageobjects/authScreens'
describe('Balance screen displays correctly', () => {
const mne = "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else typical";
it('selecting qa network', async () => {
await (await Auth.signInButton).click()
await (await Auth.signInMnemonic).click()
await (await Auth.mnemonicInput).waitForDisplayed()
await (await Auth.mnemonicInput).addValue(mne)
await (await Auth.signIn).click()
await (await Balance.networkDropdown).waitForDisplayed({timeout: 1500})
await (await Balance.networkDropdown).click()
// TO-DO fix the selector below, it's an odd one
await (await Balance.networkSelectQa).waitForDisplayed({timeout: 1500})
await (await Balance.networkSelectQa).click()
let network = await (await Balance.networkDropdown).getText()
expect(network).toStrictEqual('QA')
})
it('copy the account id', async () => {
// await (await Auth.signInButton).click()
// await (await Auth.signInMnemonic).click()
// await (await Auth.mnemonicInput).waitForDisplayed()
// await (await Auth.mnemonicInput).addValue(mne)
// await (await Auth.signIn).click()
// await (await Balance.copyAccountId).click()
})
})
@@ -0,0 +1,62 @@
import Auth from '../../pageobjects/authScreens'
import Balance from '../../pageobjects/balanceScreen'
import ValidatorClient from '@nymproject/nym-validator-client';
const textConstants = require("../../../common/text-constants");
const userData = require("../../../common/user-data.json");
describe('Create password for existing account and use it to sign in', () => {
it('enter incorrect mnemonic', async () => {
//click through sign in
await (await Auth.signInButton).click()
await (await Auth.signInMnemonic).click()
//instead of entering mnemonic, click on create a password
await (await Auth.createPassword).click()
//enter incorrect mnemonic
await (await Auth.mnemonicInput).addValue(textConstants.incorrectMnemonic)
await (await Auth.nextToPasswordCreation).click()
// assert error message is correct
let getErrorWarning = await (await Auth.error).getText()
expect(getErrorWarning).toStrictEqual(textConstants.incorrectMnemonicPasswordCreation)
})
it('enter random string', async () => {
await (await Auth.mnemonicInput).addValue(textConstants.randomString)
await (await Auth.nextToPasswordCreation).click()
let getErrorWarning = await (await Auth.error).getText()
expect(getErrorWarning).toStrictEqual(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 (await Auth.backToMnemonicSignIn).click()
await (await Auth.createPassword).click()
await (await Auth.mnemonicInput).addValue(randomMnemonic)
await (await Auth.nextToPasswordCreation).click()
await (await Auth.password).waitForDisplayed({ timeout: 2500 })
})
it('create an invalid password', async () => {
// type an invalid password in both fields
await (await Auth.password).addValue(textConstants.incorrectPassword)
await (await Auth.confirmPassword).click()
await (await Auth.confirmPassword).addValue(textConstants.incorrectPassword)
// ensure the button to proceed is still disabled
// TO-DO the next button seems to not be clickable here, despite the locator id existing in the right place
const nextButton = await Auth.next
const isNextDisabled = await nextButton.getAttribute('disabled')
expect(isNextDisabled).toBe(true)
})
})
@@ -1,8 +1,13 @@
import Auth from '../../pageobjects/authScreens'
import Balance from '../../pageobjects/balanceScreen'
const textConstants = require("../../../common/text-constants");
const userData = require("../../../common/user-data.json");
describe('Wallet sign in functionality with mnemonic', () => {
describe('Wallet login functionality', () => {
it('sign in with no mnemonic throws error', async () => {
//click through sign without entering a mnemonic
await (await Auth.signInButton).click()
await (await Auth.signInMnemonic).click()
@@ -10,17 +15,36 @@ describe('Wallet login functionality', () => {
// wait for error
await (await Auth.error).waitForDisplayed({ timeout: 1500 })
let getErrorWarning = await (await Auth.error).getText()
const errorText = 'A mnemonic must be provided'
// verify error has the correct message
expect(getErrorWarning).toStrictEqual(errorText)
// TO-DO fix the below so there's no need to go back before the following test
await (await Auth.backToSignInOptions).click()
await (await Auth.backToWelcomePage).click()
expect(getErrorWarning).toStrictEqual(textConstants.signInWithoutMnemonic)
})
it('should login with valid credentials', async () => {
it('sign in with incorrect mnemonic throws error', async () => {
// await (await Auth.mnemonicInput).waitForDisplayed()
await (await Auth.mnemonicInput).addValue(textConstants.incorrectMnemonic)
await (await Auth.signIn).click()
let getErrorWarning = await (await Auth.error).getText()
expect(getErrorWarning).toContain(textConstants.signInIncorrectMnemonic)
})
it('sign in with random string throws error', async () => {
// await (await Auth.mnemonicInput).waitForDisplayed()
await (await Auth.mnemonicInput).addValue(textConstants.randomString)
await (await Auth.signIn).click()
let getErrorWarning = await (await Auth.error).getText()
expect(getErrorWarning).toContain(textConstants.signInRandomString)
})
it('should sign in with valid credentials', async () => {
// go back to create account option
await (await Auth.backToSignInOptions).click()
await (await Auth.backToWelcomePage).click()
// create new mnemonic
await (await Auth.createAccount).click()
let mnemonic = await (await Auth.mnemonicPhrase).getText()
@@ -34,10 +58,10 @@ describe('Wallet login functionality', () => {
// verify successful login, balance is visible
await (await Balance.balance).waitForDisplayed({ timeout: 4000 })
// TO-DO the balance is not always caputred, some tests fail with ' ' not equal '0 NYM'
// TO-DO the balance is not always caputred, some tests fail with ' ' not equal '0 NYM' ??
let balance = await (await Balance.nymBalance).getText()
console.log('amountttttttt' + balance)
//new accounts will always default to mainnet, so 0 balance
expect(balance).toStrictEqual('0 NYM')
expect(balance).toStrictEqual(textConstants.noNym)
})
})
@@ -0,0 +1,53 @@
import Auth from '../../pageobjects/authScreens'
import Balance from '../../pageobjects/balanceScreen'
const textConstants = require("../../../common/text-constants");
const userData = require("../../../common/user-data.json");
const deleteWallet = require("../../../scripts/deletesavedwallet");
const walletExists = require("../../../scripts/savedwalletexists")
describe('Wallet sign in functionality with password', () => {
it('sign in with no password throws error', async () => {
//click through sign without entering a password
await (await Auth.signInButton).click()
await (await Auth.signInPassword).click()
await (await Auth.signInPasswordButton).click()
// wait for error
await (await Auth.error).waitForDisplayed({ timeout: 1500 })
let getErrorWarning = await (await Auth.error).getText()
// verify error has the correct message
expect(getErrorWarning).toStrictEqual(textConstants.signInWithoutPassword)
})
it('sign in with invalid password throws error', async () => {
// enter invalid password
await (await Auth.enterPassword).addValue(textConstants.incorrectPassword)
await (await Auth.signInPasswordButton).click()
// wait for error
await (await Auth.error).waitForDisplayed({ timeout: 1500 })
let getErrorWarning = await (await Auth.error).getText()
// TO-DO GET BACK TO THIS LOGIC. It's currently only searching for the second condition (if the wallet json file doesn't exist)
const scriptExist = walletExists.doesFileExist
scriptExist ? expect(getErrorWarning).toStrictEqual(textConstants.invalidPasswordOnSignIn) : expect(getErrorWarning).toStrictEqual(textConstants.failedToFindWalletFile)
})
it('sign in with invalid password and no saved wallet.json file throws error', async () => {
// shell script to remove the json file
deleteWallet.deleteSavedFile
// enter invalid password
await (await Auth.enterPassword).addValue(textConstants.incorrectPassword)
await (await Auth.signInPasswordButton).click()
// wait for error
await (await Auth.error).waitForDisplayed({ timeout: 1500 })
let getErrorWarning = await (await Auth.error).getText()
expect(getErrorWarning).toStrictEqual(textConstants.failedToFindWalletFile)
})
})
@@ -0,0 +1,72 @@
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 Unbond from '../../pageobjects/unbondScreen'
import Delegation from '../../pageobjects/delegationScreen'
const userData = require("../../../common/user-data.json");
describe('Nav Items behave correctly', () => {
it('switch from light to dark mode and back', async () => {
//log in
await Auth.loginWithMnemonic(userData.mnemonic)
// click on different modes
await (await Nav.lightMode).waitForDisplayed({ timeout: 4000 })
await (await Nav.lightMode).click()
await (await Nav.darkMode).click()
await (await Nav.lightMode).waitForDisplayed({ timeout: 2500 })
})
it('clicking terminal opens the modal', async () => {
await (await Nav.terminalIcon).click()
let terminalTitle = await (await Nav.terminalTitle).getText()
expect(terminalTitle).toContain('Terminal')
})
})
describe('Menu items lead to correct screen', () => {
it('check Balance link works', async () => {
await (await Nav.balance).click()
let balanceTitle = await (await Balance.balance).getText()
expect(balanceTitle).toContain('Balance')
})
it('check Send link works', async () => {
await (await Nav.send).click()
let sendTitle = await (await Send.sendHeader).getText()
expect(sendTitle).toContain('Send')
await (await Nav.closeIcon).click()
})
it('check Receive link works', async () => {
await (await Nav.receive).click()
let receiveNymTitle = await (await Receive.receiveNymTitle).getText()
expect(receiveNymTitle).toContain('Receive NYM')
})
it('check Bond link works', async () => {
await (await Nav.bond).click()
let bondTitle = await (await Bond.bondTitle).getText()
expect(bondTitle).toContain('Bond')
})
it('check Unbond link works', async () => {
await (await Nav.unbond).click()
let unbondTitle = await (await Unbond.unbondTitle).getText()
expect(unbondTitle).toContain('Unbond')
})
it('check Delegation link works', async () => {
await (await Nav.delegation).click()
let delegationTitle = await (await Delegation.delegationTitle).getText()
expect(delegationTitle).toContain('Delegation')
})
})
@@ -0,0 +1,83 @@
import Auth from '../../pageobjects/authScreens'
import Balance from '../../pageobjects/balanceScreen'
const textConstants = require("../../../common/text-constants");
const userData = require("../../../common/user-data.json");
describe('Create a new account and verify it exists', () => {
it('generate new mnemonic and verify mnemonic words', async () => {
await (await Auth.createAccount).click()
await (await Auth.mnemonicPhrase).waitForDisplayed({ timeout: 2500 })
let mnemonic = await (await Auth.mnemonicPhrase).getText()
let arrayMnemonic = mnemonic.split(" ")
await (await Auth.copyMnemonic).click()
await (await expect(Auth.iSavedMnemonic).toBeClickable())
await (await Auth.iSavedMnemonic).click()
let mnemonicWordTiles = await (await Auth.mnemonicWordTile)
let wordTileIndex = await (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
const isNextDisabled = await nextButton.getAttribute('disabled')
expect(isNextDisabled).toBe(null)
})
it('click skip password', async () => {
await (await Auth.nextToStep3).click()
await (await Auth.skipPasswordAndSignInWithMnemonic).click()
await (await Auth.mnemonicInput).waitForDisplayed({ timeout: 1500 })
await (await Auth.backToSignInOptions).click()
})
it('set up invalid password for new account', async () => {
await (await Auth.password).click()
await (await Auth.password).addValue(textConstants.incorrectPassword)
await (await Auth.confirmPassword).click()
await (await Auth.confirmPassword).addValue(textConstants.incorrectPassword)
const nextButton = await Auth.next
const isNextDisabled = await nextButton.getAttribute('disabled')
expect(isNextDisabled).toBe("true")
})
it('set up valid password for new account', async () => {
await (await Auth.password).click()
await (await Auth.password).addValue(textConstants.password)
await (await Auth.confirmPassword).click()
await (await Auth.confirmPassword).addValue(textConstants.password)
const nextButton = await Auth.next
const isNextDisabled = await nextButton.getAttribute('disabled')
expect(isNextDisabled).toBe(null)
})
it('proceed to login with newly created password', async () => {
await (await Auth.next).click()
await (await Auth.enterPassword).waitForDisplayed({ timeout: 1500 })
await (await Auth.enterPassword).addValue(textConstants.password)
await (await Auth.signInPasswordButton).click()
await (await Balance.balance).waitForDisplayed({ timeout: 4000 })
let balance = await (await Balance.nymBalance).getText()
//new accounts will always default to mainnet, so 0 balance
expect(balance).toStrictEqual(textConstants.noNym)
})
})
@@ -1,74 +0,0 @@
import Auth from '../../pageobjects/authScreens'
import Balance from '../../pageobjects/balanceScreen'
describe('Create a new account and verify it exists', () => {
it('clicking on create account generates new mnemonic', async () => {
await (await Auth.createAccount).click()
await (await Auth.mnemonicPhrase).waitForDisplayed({ timeout : 1000})()
await (await Auth.copyMnemonic).click()
await (await expect(Auth.iSavedMnemonic).toBeClickable())
})
it('complete new account creation', async () => {
await (await Auth.createAccount).click()
let mnemonic = await (await Auth.mnemonicPhrase).getText()
let arrayMnemonic = mnemonic.split(" ")
// the below will print out the second word of the mnemonic saved
console.log(arrayMnemonic[1]);
await (await Auth.copyMnemonic).click()
await (await Auth.iSavedMnemonic).click()
// for each number, find the equivalent index from arrayMnemonic, capture word, then find word in mnemonicWord, and click it
// OR for each word, find the index+1 and match it to the number seen on the screen
await (await Auth.number).waitForDisplayed()
let itemNumber = await (await Auth.number).getText()
let word = await (await Auth.mnemonicWord).getText()
arrayMnemonic.forEach(function (item, index) {
console.log(item, index);
for (let num = 0; num < 6; num++) {
if ((index + 1) == itemNumber) {
console.log('mne word ' + word)
Auth.mnemonicWord.click()
}
}
})
// for (let num = 0; num < 6; num++) {
// await (await Auth.number).forEach(item => {
// let numb = item.getText()
// const itemArray = Array.from(numb)
// console.log('the numberrr ' + itemArray)
// })
// }
// const test = arrayMnemonic.some(word => word.index = itemNumber);
// console.log('the test again ' + test);
// await (await Auth.mnemonicWord).click()
// var values = [];
// let numbers = await (await Auth.number).()
// for (var i = 0; i < numbers.length; i++) {
// values.push(numbers[i].value);
// }
// var numm = (Auth.number).children;
// const numarray = Array.from(numm);
// numarray.push;
// console.log('the numbers ' + numarray)
// the below will print out the text of the first mnemonic button
let text = await (await Auth.mnemonicWord).getText([1])
console.log('the mnemonic texttttt' + text)
await (await Auth.mnemonicWord).click()
})
})
+9 -2
View File
@@ -1,7 +1,14 @@
{
"compilerOptions": {
"types": ["node", "webdriverio/async", "@wdio/mocha-framework", "expect-webdriverio"],
"types": [
"node",
"webdriverio/async",
"@wdio/mocha-framework",
"expect-webdriverio"
],
"target": "ES5"
},
"include": ["wallet-ui-tests/*"]
"include": [
"wallet-ui-tests/*"
]
}
+4 -1
View File
@@ -17,7 +17,7 @@ exports.config = {
specs: ['./tests/specs/**/*.ts'],
suites: {
welcome: [
signup: [
'./tests/specs/newaccount/*.ts',
],
login: [
@@ -26,6 +26,9 @@ exports.config = {
balance: [
'./tests/specs/balance/*.ts',
],
nav: [
'./tests/specs/navbaritems/*.ts',
],
},
// Patterns to exclude.
exclude: [
-5
View File
@@ -1,5 +0,0 @@
reports
allure-results
node_modules
.vscode
.idea
-86
View File
@@ -1,86 +0,0 @@
<!--
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.
-12
View File
@@ -1,12 +0,0 @@
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
node: "14",
},
},
],
],
};
@@ -1,30 +0,0 @@
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",
};
@@ -1,43 +0,0 @@
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();
-34
View File
@@ -1,34 +0,0 @@
{
"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 .",
"test:temp": "wdio run wdio.conf.cjs --suite temp",
"test": "wdio run wdio.conf.ts"
},
"dependencies": {
"@types/node": "^16.11.0",
"@wdio/allure-reporter": "^7.16.1",
"@wdio/cli": "^7.9.1",
"@zxing/browser": "^0.0.9",
"@nymproject/nym-validator-client": "^0.19.0",
"ts-node": "^10.6.0"
},
"devDependencies": {
"@wdio/local-runner": "^7.14.1",
"@wdio/mocha-framework": "^7.14.1",
"@wdio/spec-reporter": "^7.14.1",
"prettier": "2.4.1",
"typescript": "^4.6.2"
}
}
@@ -1,48 +0,0 @@
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();
@@ -1,48 +0,0 @@
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();
@@ -1,24 +0,0 @@
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();
@@ -1,60 +0,0 @@
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();
@@ -1,42 +0,0 @@
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();
@@ -1,31 +0,0 @@
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();
@@ -1,37 +0,0 @@
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();
@@ -1,52 +0,0 @@
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();
@@ -1,22 +0,0 @@
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();
@@ -1,54 +0,0 @@
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);
});
});
@@ -1,108 +0,0 @@
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);
});
});
@@ -1,45 +0,0 @@
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);
});
});
@@ -1,28 +0,0 @@
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);
});
});
@@ -1,55 +0,0 @@
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);
});
});
@@ -1,32 +0,0 @@
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);
});
});
@@ -1,39 +0,0 @@
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();
});
});
@@ -1,32 +0,0 @@
import ValidatorClient from '@nymproject/nym-validator-client';
describe('Creating valid account', () => {
it('send nyms from one account to another', async () =>{
const benny = "giraffe note order sun cradle bottom crime humble able antique rural donkey guess parent potato tongue truly way disagree exile zebra someone else typical";
const mnemonic = ValidatorClient.randomMnemonic();
console.log(ValidatorClient);
const newAccountClient = await ValidatorClient.connect(mnemonic,
'https://qa-validator.nymtech.net', 'https://qa-validator-api.nymtech.net/api', 'n', 'n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep', 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav', 'nym');
const address = newAccountClient.address;
console.log({ address, mnemonic });
const client = await ValidatorClient.connect(
benny, 'https://qa-validator.nymtech.net', 'https://qa-validator-api.nymtech.net/api', 'n', 'n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep', 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav', 'nym');
await client.send(address, [{ amount: '10000000', denom: 'unym' }]);
const balance = await client.getBalance(address);
console.log({ balance });
expect(Number.parseFloat(balance.amount)).toBe(10000000);
}).timeout(5000);
})
// the newly created address from the test above:
// address: 'n13l7rwrygs0m3kx3en2eh55dtmwlzm0vskw0hxq',
// mnemonic: 'tree upset require kitten inquiry truck emotion ladder reject elbow page ability spot win board frog child much credit pizza picture hover medal zoo'
// always make sure it's on QA, unless youre on debug branch (~look in nym_path wdio.config.ts to check)
// ENABLE_QA_MODE=true target/release/nym-wallet
-6
View File
@@ -1,6 +0,0 @@
{
"compilerOptions": {
"types": ["node", "webdriverio/async", "@wdio/mocha-framework", "expect-webdriverio"],
"target": "ES5"
}
}
-94
View File
@@ -1,94 +0,0 @@
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"],
temp:["./tests/specs/temp/temp.spec.ts"],
},
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(),
};
-87
View File
@@ -1,87 +0,0 @@
const os = require('os')
const path = require('path')
const { spawn, spawnSync } = require('child_process')
//insert path to binary
const nym_path = '../target/debug/nym_wallet'
let tauriDriver: any
exports.config = {
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
transpileOnly: true,
project: 'tsconfig.json',
},
},
specs: ['./tests/specs/**/*.ts'],
suites: {
welcome: [
'./tests/specs/newaccount/*.ts',
]},
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
'tauri:options': {
application: nym_path,
},
},
],
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: 'info',
bail: 0,
framework: 'mocha',
reporters: ['spec'],
mochaOpts: {
ui: 'bdd',
timeout: 60000,
},
// ===================
// 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(),
}
@@ -27,7 +27,7 @@ export const CopyToClipboard: React.FC<{
{showConfirmation ? (
<DoneIcon color="success" sx={sx} />
) : (
<ContentCopyIcon onClick={handleCopy} sx={{ cursor: 'pointer', ...sx }} />
<ContentCopyIcon data-testid="ContentCopyIcon" onClick={handleCopy} sx={{ cursor: 'pointer', ...sx }} />
)}
</Tooltip>
);