diff --git a/app/README.md b/app/README.md index 02aac3f..793431c 100644 --- a/app/README.md +++ b/app/README.md @@ -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.\ diff --git a/app/package.json b/app/package.json index 14adca2..b368a79 100644 --- a/app/package.json +++ b/app/package.json @@ -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", diff --git a/app/src/components/BglToWbgl.js b/app/src/components/BglToWbgl.js index 29ddab1..42438ae 100644 --- a/app/src/components/BglToWbgl.js +++ b/app/src/components/BglToWbgl.js @@ -37,9 +37,9 @@ function BglToWbgl() { return !sendAddress ? ( -
+ - + @@ -49,12 +49,12 @@ function BglToWbgl() { ) : ( - Send BGL to: {sendAddress} + Send BGL to: {sendAddress} - The currently available WBGL balance is {balance}. 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 {balance}. If you send more BGL than is available to complete the exchange, your BGL will be returned to your address. - Please note, that a fee of {feePercentage}% will be automatically deducted from the transfer amount. This exchange pair is active for 7 days. + Please note, that a fee of {feePercentage}% will be automatically deducted from the transfer amount. This exchange pair is active for 7 days. ) diff --git a/app/src/components/ConnectWallet.js b/app/src/components/ConnectWallet.js index 97ad3f3..26d100f 100644 --- a/app/src/components/ConnectWallet.js +++ b/app/src/components/ConnectWallet.js @@ -21,6 +21,9 @@ function ConnectWallet() { case 'connected': return () + default: + return () + } } diff --git a/app/src/components/WbglToBgl.js b/app/src/components/WbglToBgl.js index d44f034..7938e15 100644 --- a/app/src/components/WbglToBgl.js +++ b/app/src/components/WbglToBgl.js @@ -1,6 +1,6 @@ -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, @@ -8,8 +8,8 @@ import { 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() { @@ -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) @@ -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 ( - + - + ) } 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 } @@ -91,15 +92,16 @@ function WbglToBgl() { } return ( -
+ @@ -110,22 +112,22 @@ function WbglToBgl() { return ( - - - + + + {!sendAddress ? ( - + ) : ( - The currently available BGL balance is {balance}. If you send more WBGL than is available to complete + The currently available BGL balance is {balance}. If you send more WBGL than is available to complete the exchange, your WBGL will be returned to your address. - Please note, that a fee of {feePercentage}% will be automatically deducted from the transfer amount. + Please note, that a fee of {feePercentage}% will be automatically deducted from the transfer amount. - + )} diff --git a/app/src/tests/components/App.test.js b/app/src/tests/components/App.test.js new file mode 100644 index 0000000..68bd6a8 --- /dev/null +++ b/app/src/tests/components/App.test.js @@ -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( + + + + ) + // 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() + + }) + +}) \ No newline at end of file diff --git a/app/src/tests/components/BglToWbgl.test.js b/app/src/tests/components/BglToWbgl.test.js new file mode 100644 index 0000000..0fec1cd --- /dev/null +++ b/app/src/tests/components/BglToWbgl.test.js @@ -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( + + + + ) + + 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( + + + + ) + + 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 }) + + }) + +}) \ No newline at end of file diff --git a/app/src/tests/components/CheckWalletConnection.test.js b/app/src/tests/components/CheckWalletConnection.test.js new file mode 100644 index 0000000..d1a922c --- /dev/null +++ b/app/src/tests/components/CheckWalletConnection.test.js @@ -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 =

Test text

+ render( + + + {dummyChild} + + + ) + + expect(await screen.findByText(/Test text/)).toBeInTheDocument() + + + }) +}) \ No newline at end of file diff --git a/app/src/tests/components/ConnectWallet.test.js b/app/src/tests/components/ConnectWallet.test.js new file mode 100644 index 0000000..f864c4b --- /dev/null +++ b/app/src/tests/components/ConnectWallet.test.js @@ -0,0 +1,48 @@ +import '@testing-library/jest-dom/extend-expect' +import { render, screen, waitFor } from '@testing-library/react' +import userEvent from '@testing-library/user-event' + +import {useMetaMask, MetaMaskProvider} from 'metamask-react' +import ConnectWallet from '../../components/ConnectWallet' + +const ROPSTEN_TESTNET_CHAINID = 3 +const ROPSTEN_TESTNET_ACCOUNT = '0xBCEeB54fa604FB357750E76229ADf98DfA90580f' + +// mock only the hook +// mock only the function then swap out the implementation +jest.mock('metamask-react', () => { + return { + ...jest.requireActual('metamask-react'), + useMetaMask: () => ({ + status: 'connected', + chainId: ROPSTEN_TESTNET_CHAINID, + account: ROPSTEN_TESTNET_ACCOUNT, + connect: jest.fn() + }) + } +}) + +describe('ConnectWallet component Test', () => { + + + afterEach(() => { + jest.clearAllMocks() + }) + + afterAll(() => { + jest.resetAllMocks() + }) + + test('renders ConnectWallet component', () => { + + const { getByRole } = render( + + + + ) + + + expect(screen.getByText('Ethereum')).toBeInTheDocument() + }) + +}) \ No newline at end of file diff --git a/app/src/tests/components/Footer.test.js b/app/src/tests/components/Footer.test.js new file mode 100644 index 0000000..228f83c --- /dev/null +++ b/app/src/tests/components/Footer.test.js @@ -0,0 +1,17 @@ +import { render, screen, waitFor } from '@testing-library/react' +import '@testing-library/jest-dom/extend-expect' + +import Footer from '../../components/Footer' + +describe('Footer Component Tests', () => { + + it('it should render Footer component', () => { + render(