Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests to front-end part of the app #17

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9df9204
Add unit tests for `app/src/components/App` component
naftalimurgor Sep 11, 2022
5386150
add unit tests for `app/src/components/Footer` component
naftalimurgor Sep 11, 2022
bd5cb1f
add unit tests for `app/src/components/BglToWbgl` component
naftalimurgor Sep 11, 2022
f7855d9
add unit tests for `app/src/components/Header` component
naftalimurgor Sep 11, 2022
3600cf4
add unit tests for `app/src/components/WbglToBgl` component
naftalimurgor Sep 11, 2022
422945c
add unit tests for `app/src/utils` utility functions
naftalimurgor Sep 11, 2022
04bf94e
update `app/README.md` add `tests` location
naftalimurgor Sep 11, 2022
7ff2682
Merge branch 'main' into add-app-unit-tests
0xswakei Oct 16, 2022
d009c67
add `data-testid`s tags for querying `JSX` for `apps/BglToWbgl` compo…
0xswakei Oct 23, 2022
c1310ed
add `data-testid`s tags for querying `JSX` for `apps/ConnectWallet` c…
0xswakei Oct 23, 2022
605bc58
add `data-testid`s tags for querying `JSX` for `apps/WbglToBgl` compo…
0xswakei Oct 23, 2022
157b26a
update `tests/App.test.js` to work with ( #14 )
0xswakei Oct 23, 2022
cf699ee
update `tests/BglToWbgl.test.js` to work with ( #14 )
0xswakei Oct 23, 2022
10dbae5
update `tests/WbglToBgl.test.js` to work with ( #14 )
0xswakei Oct 23, 2022
f1d76b3
update `tests/Header.test.js` to work with ( #14 )
0xswakei Oct 23, 2022
145abd2
add unit test for `components/CheckWalletConnection`
0xswakei Oct 23, 2022
652103e
add unit tests for `components/ConnectWallet` component ( #14 )
0xswakei Oct 23, 2022
3c859be
bump `@testing-library/user-event` to version `v14.0.0`
0xswakei Oct 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

NB: All tests are located under `src/tests`.

### `yarn build`

Builds the app for production to the `build` folder.\
Expand Down
3 changes: 2 additions & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"@material-ui/core": "^4.11.4",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "14",
"metamask-react": "^2.4.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
10 changes: 5 additions & 5 deletions app/src/components/BglToWbgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ function BglToWbgl() {

return !sendAddress ? (
<CheckWalletConnection>
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off">
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off" data-testid='send-form'>
<List>
<ListItemText primary="Chain:" secondary={chainLabel(chainId)}/>
<ListItemText primary="Chain:" secondary={chainLabel(chainId)}/>
<ListItemText primary={`Receiving Address:`} secondary={account}/>
</List>
<Box display="flex" justifyContent="center" m={1}>
Expand All @@ -49,12 +49,12 @@ function BglToWbgl() {
</CheckWalletConnection>
) : (
<Fragment>
<Typography variant="body1" gutterBottom>Send BGL to: <code>{sendAddress}</code></Typography>
<Typography variant="body1" gutterBottom>Send BGL to: <code data-testid='send-address'>{sendAddress}</code></Typography>
<Typography variant="body2" gutterBottom>
The currently available WBGL balance is <b>{balance}</b>. If you send more BGL than is available to complete the exchange, your BGL will be returned to your address.
The currently available WBGL balance is <b data-testid="balance">{balance}</b>. If you send more BGL than is available to complete the exchange, your BGL will be returned to your address.
</Typography>
<Typography variant="body2" gutterBottom>
Please note, that a fee of <b>{feePercentage}%</b> will be automatically deducted from the transfer amount. This exchange pair is active for <b>7 days</b>.
Please note, that a fee of <b data-testid='fee-percentage'>{feePercentage}%</b> will be automatically deducted from the transfer amount. This exchange pair is active for <b>7 days</b>.
</Typography>
</Fragment>
)
Expand Down
3 changes: 3 additions & 0 deletions app/src/components/ConnectWallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ function ConnectWallet() {

case 'connected':
return (<Chip label={chainLabel(chainId)} color={isChainValid(chainId) ? 'primary' : 'secondary'}/>)
default:
return (<Button variant="contained" color="secondary" onClick={connect}>Connect</Button>)

}
}

Expand Down
46 changes: 24 additions & 22 deletions app/src/components/WbglToBgl.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {Fragment, useState} from 'react'
import {useMetaMask} from 'metamask-react'
import {useForm} from 'react-hook-form'
import { Fragment, useState } from 'react'
import { useMetaMask } from 'metamask-react'
import { useForm } from 'react-hook-form'
import {
Box,
Button,
List, ListItemText,
TextField,
Typography,
} from '@material-ui/core'
import {chainLabel, isChainBsc, post, url} from '../utils'
import {sendWbgl, useWbglBalance} from '../utils/wallet'
import { chainLabel, isChainBsc, post, url } from '../utils'
import { sendWbgl, useWbglBalance } from '../utils/wallet'
import CheckWalletConnection from './CheckWalletConnection'

function WbglToBgl() {
Expand All @@ -18,11 +18,11 @@ function WbglToBgl() {
const [balance, setBalance] = useState(0)
const [feePercentage, setFeePercentage] = useState(0)
const wbglBalance = useWbglBalance()
const {chainId, account, ethereum} = useMetaMask()
const { chainId, account, ethereum } = useMetaMask()
const chain = isChainBsc(chainId) ? 'bsc' : 'eth'

const AddressForm = () => {
const {register, handleSubmit, setError, setFocus, formState: {errors}} = useForm()
const { register, handleSubmit, setError, setFocus, formState: { errors } } = useForm()

const onSubmit = async data => {
setSubmitting(true)
Expand All @@ -48,40 +48,41 @@ function WbglToBgl() {
setFeePercentage(response.feePercentage)
}).catch(result => {
if (result.hasOwnProperty('field')) {
setError(result.field, {type: 'manual', message: result.message})
setError(result.field, { type: 'manual', message: result.message })
setFocus(result.field)
}
}).finally(() => setSubmitting(false))
}

return (
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off">
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off" data-testid="bgl-address-form">
<TextField
data-testid="address-input"
variant="filled"
margin="normal"
label="BGL Address"
fullWidth
required
helperText={errors['bglAddress'] ? 'Please enter a valid Bitgesell address.' : 'Enter the BGL address coins will be sent to.'}
{...register('bglAddress', {required: true, pattern: /^(bgl1|[135])[a-zA-HJ-NP-Z0-9]{25,39}$/i})}
{...register('bglAddress', { required: true, pattern: /^(bgl1|[135])[a-zA-HJ-NP-Z0-9]{25,39}$/i })}
error={!!errors['bglAddress']}
/>
<Box display="flex" justifyContent="center" m={1}>
<Button type="submit" variant="contained" color="primary" size="large" disabled={submitting}>Continue</Button>
<Button type="submit" variant="contained" color="primary" size="large" disabled={submitting} data-testid='step-1'>Continue</Button>
</Box>
</form>
)
}

const SendForm = () => {
const {register, handleSubmit, setError, formState: {errors}} = useForm()
const { register, handleSubmit, setError, formState: { errors } } = useForm()

const onSubmit = async data => {
const amount = parseFloat(data.amount)
const balance = parseFloat(wbglBalance)

if (!amount || !balance || amount > balance) {
setError('amount', {type: 'manual', message: 'Not enough WBGL available!', shouldFocus: true})
setError('amount', { type: 'manual', message: 'Not enough WBGL available!', shouldFocus: true })
return
}

Expand All @@ -91,15 +92,16 @@ function WbglToBgl() {
}

return (
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off">
<form onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off" data-testid="send-wbgl-form">
<TextField
data-testid="wbgl-amount-input"
variant="filled"
margin="normal"
label="WBGL Amount"
fullWidth
required
helperText={errors['amount'] ? 'Please enter a valid amount.' : 'Enter the amount of tokens to send.'}
{...register('amount', {required: true, pattern: /^[0-9]+\.?[0-9]*$/i})}
{...register('amount', { required: true, pattern: /^[0-9]+\.?[0-9]*$/i })}
error={!!errors['amount']}
/>
<Button type="submit" variant="contained" color="primary" size="large" disabled={submitting}>Send WBGL</Button>
Expand All @@ -110,22 +112,22 @@ function WbglToBgl() {
return (
<CheckWalletConnection>
<List>
<ListItemText primary="Chain:" secondary={chainLabel(chainId)}/>
<ListItemText primary={`Source Address:`} secondary={account}/>
<ListItemText primary="WBGL Balance:" secondary={wbglBalance}/>
<ListItemText primary="Chain:" secondary={chainLabel(chainId)} />
<ListItemText data-testid='source-address' primary={`Source Address:`} secondary={account} />
<ListItemText data-testid='balance' primary="WBGL Balance:" secondary={wbglBalance} />
</List>
{!sendAddress ? (
<AddressForm/>
<AddressForm />
) : (
<Fragment>
<Typography variant="body2" gutterBottom>
The currently available BGL balance is <b>{balance}</b>. If you send more WBGL than is available to complete
The currently available BGL balance is <b data-testid='balance'>{balance}</b>. If you send more WBGL than is available to complete
the exchange, your WBGL will be returned to your address.
</Typography>
<Typography variant="body2" gutterBottom>
Please note, that a fee of <b>{feePercentage}%</b> will be automatically deducted from the transfer amount.
Please note, that a fee of <b data-testid='fee-percentage'>{feePercentage}%</b> will be automatically deducted from the transfer amount.
</Typography>
<SendForm/>
<SendForm />
</Fragment>
)}

Expand Down
25 changes: 25 additions & 0 deletions app/src/tests/components/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { render, screen, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { MetaMaskProvider } from 'metamask-react'
import App from '../../components/App'

describe('App Tests', () => {
test('it should render App component', () => {
render(
<MetaMaskProvider>
<App />
</MetaMaskProvider>
)
// screen.debug()
const linkElement = screen.getByRole('link')
const imgElement = screen.getByRole('img')
const tabButtonElement = screen.getAllByRole('tab')

expect(linkElement).toBeInTheDocument()
expect(imgElement).toBeInTheDocument()
// mutliple tabs, atleast one should be in the DOM
expect(tabButtonElement[0]).toBeInTheDocument()

})

})
107 changes: 107 additions & 0 deletions app/src/tests/components/BglToWbgl.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { render, screen, act, fireEvent, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'

import BglToWbgl from '../../components/BglToWbgl'
import * as utils from '../../utils'

import { MetaMaskProvider } from 'metamask-react'

const ROPSTEN_TESTNET_CHAINID = 3
const ROPSTEN_TESTNET_ACCOUNT = '0xBCEeB54fa604FB357750E76229ADf98DfA90580f'
const BITGESEL_TEST_ACCOUNT = 'qcBCEeB54fa604FB357750E76229ADf98DfA90580f'

const mockHandleSubmit = jest.fn()
jest.mock('react-hook-form', () => {
return {
...jest.requireActual('react-hook-form'),
useForm: () => ({
register: jest.fn(),
handleSubmit: mockHandleSubmit,
setError: jest.fn(),
setFocus: jest.fn(),
formState: { errors: {} }
})
}
})

// mock only the hook
jest.mock('metamask-react', () => {
return {
...jest.requireActual('metamask-react'),
useMetaMask: () => ({
status: 'connected',
chainId: ROPSTEN_TESTNET_CHAINID,
account: ROPSTEN_TESTNET_ACCOUNT,
connect: jest.fn()
})
}
})

describe('BglToWbgl Component Tests', () => {

beforeEach(() => {
window.HTMLFormElement.prototype.submit = () => jest.fn()
})
afterEach(() => {
jest.clearAllMocks()
})

test('should render BglToWbgl component when MetaMask wallet is connected', async () => {
render(
<MetaMaskProvider>
<BglToWbgl />
</MetaMaskProvider>
)

await waitFor(async () => {
await screen.findByText(new RegExp(ROPSTEN_TESTNET_ACCOUNT, 'ig'))
await screen.findByText(new RegExp(ROPSTEN_TESTNET_CHAINID), 'ig')

expect(await screen.findByText(new RegExp(ROPSTEN_TESTNET_CHAINID, 'ig'))).toBeInTheDocument()
expect(await screen.findByText(new RegExp(ROPSTEN_TESTNET_CHAINID, 'ig'))).toBeInTheDocument()
}, { timeout: 4000 })

})

test('should send Bgl To Wbgl when user has connected MetaMask Wallet', async () => {

render(
<MetaMaskProvider>
<BglToWbgl />
</MetaMaskProvider>
)

const spy = jest.spyOn(window, 'fetch')

const mockBglResponse = {
bglAddress: BITGESEL_TEST_ACCOUNT,
balance: Math.floor(Math.random() * 10),
feePercentage: Math.random()
}

const spyPost = jest.spyOn(utils, 'post')

const mockedPost = spyPost.mockImplementation((url, data = {}) => {
return Promise.resolve(mockBglResponse)
})

const { bglAddress, balance, feePercentage } = await mockedPost()
fireEvent.click(screen.getByRole('button'))


await waitFor(async () => {
await screen.findByText(new RegExp(ROPSTEN_TESTNET_ACCOUNT, 'ig'))
await screen.findByText(new RegExp(balance), 'ig')
const recepientAddress = await screen.findByText(new RegExp(ROPSTEN_TESTNET_ACCOUNT, 'ig'))

const sendForm = screen.getByTestId('send-form')
fireEvent.submit(sendForm)
await waitFor(() => expect(mockHandleSubmit).toHaveBeenCalled())
waitFor(() => expect(recepientAddress).toBeInTheDocument())


}, { timeout: 4000 })

})

})
44 changes: 44 additions & 0 deletions app/src/tests/components/CheckWalletConnection.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import '@testing-library/jest-dom/extend-expect'
import { render, screen, waitFor } from '@testing-library/react'
import * as metamaskReact from 'metamask-react'
import CheckWalletConnection from '../../components/CheckWalletConnection'

const ROPSTEN_TESTNET_CHAINID = 3
const ROPSTEN_TESTNET_ACCOUNT = '0xBCEeB54fa604FB357750E76229ADf98DfA90580f'
const MetaMaskProvider = metamaskReact.MetaMaskProvider

// mock only the hook
jest.mock('metamask-react', () => {
return {
...jest.requireActual('metamask-react'),
useMetaMask: () => ({
status: 'connected',
chainId: ROPSTEN_TESTNET_CHAINID,
account: ROPSTEN_TESTNET_ACCOUNT,
connect: jest.fn()
})
}
})


describe('CheckWallectConnection component Test', () => {

afterEach(() => {
jest.clearAllMocks()
})

test('Should render child props when MetaMask wallet has been connected', async () => {
const dummyChild = <p>Test text</p>
render(
<MetaMaskProvider>
<CheckWalletConnection>
{dummyChild}
</CheckWalletConnection>
</MetaMaskProvider>
)

expect(await screen.findByText(/Test text/)).toBeInTheDocument()


})
})
Loading