Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/components/Etokens/__tests__/TokenActions.test.js
| Show All 40 Lines | |||||
| import { Agora } from 'ecash-agora'; | import { Agora } from 'ecash-agora'; | ||||
| import { token as tokenConfig } from 'config/token'; | import { token as tokenConfig } from 'config/token'; | ||||
| import { explorer } from 'config/explorer'; | import { explorer } from 'config/explorer'; | ||||
| import { | import { | ||||
| FIRMA, | FIRMA, | ||||
| FIRMA_REDEEM_ADDRESS, | FIRMA_REDEEM_ADDRESS, | ||||
| XECX_SWEEPER_ADDRESS, | XECX_SWEEPER_ADDRESS, | ||||
| } from 'constants/tokens'; | } from 'constants/tokens'; | ||||
| import { | |||||
| FIRMA_DISPLAY_NAME, | |||||
| FIRMA_DISPLAY_TICKER, | |||||
| } from 'constants/tokenDisplayOverrides'; | |||||
| describe('<Token /> available actions rendered', () => { | describe('<Token /> available actions rendered', () => { | ||||
| const ecc = new Ecc(); | const ecc = new Ecc(); | ||||
| let mockedChronik; | let mockedChronik; | ||||
| // We need mockAgora now that we are using agora to subscribe to websockets | // We need mockAgora now that we are using agora to subscribe to websockets | ||||
| let mockAgora; | let mockAgora; | ||||
| beforeEach(async () => { | beforeEach(async () => { | ||||
| const mockedDate = new Date('2022-01-01T12:00:00.000Z'); | const mockedDate = new Date('2022-01-01T12:00:00.000Z'); | ||||
| ▲ Show 20 Lines • Show All 2,310 Lines • ▼ Show 20 Lines | it('We can redeem 1 Firma for $1 of XEC using a workflow unique to Firma', async () => { | ||||
| <CashtabTestWrapper | <CashtabTestWrapper | ||||
| chronik={mockedChronik} | chronik={mockedChronik} | ||||
| ecc={ecc} | ecc={ecc} | ||||
| agora={agora} | agora={agora} | ||||
| route={`/send-token/${FIRMA.tokenId}`} | route={`/send-token/${FIRMA.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = FIRMA.token.genesisInfo; | const { tokenName } = { tokenName: FIRMA_DISPLAY_NAME }; | ||||
| // Wait for element to get token info and load | // Wait for element to get token info and load | ||||
| expect( | expect( | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect( | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | await screen.findByRole('button', { name: '+ Buy' }), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Click Redeem to show the redeem form | // Click Redeem to show the redeem form | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { name: '− Redeem' }), | await screen.findByRole('button', { name: '− Redeem' }), | ||||
| ); | ); | ||||
| // The redeem button is disabled on load | // The redeem button is disabled on load | ||||
| const redeemButton = await screen.findByRole('button', { | const redeemButton = await screen.findByRole('button', { | ||||
| name: /Redeem FIRMA for XEC/, | name: /Redeem FIRMA ALPHA for XEC/, | ||||
| }); | }); | ||||
| await waitFor(() => expect(redeemButton).toBeDisabled()); | await waitFor(() => expect(redeemButton).toBeDisabled()); | ||||
| // We do not see a price input | // We do not see a price input | ||||
| expect( | expect( | ||||
| screen.queryByPlaceholderText('Enter list price (per token)'), | screen.queryByPlaceholderText('Enter list price (per token)'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // We do not see a min qty input | // We do not see a min qty input | ||||
| expect( | expect( | ||||
| screen.queryByPlaceholderText('Min qty'), | screen.queryByPlaceholderText('Min qty'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // Enter amount to redeem | // Enter amount to redeem | ||||
| await userEvent.type(screen.getByPlaceholderText('Total qty'), '0.009'); | await userEvent.type(screen.getByPlaceholderText('Total qty'), '0.009'); | ||||
| // This is below firma min redemption so we get an error | // This is below firma min redemption so we get an error | ||||
| expect( | expect( | ||||
| screen.getByText('Cannot redeem less than 0.01 FIRMA'), | screen.getByText('Cannot redeem less than 0.01 FIRMA ALPHA'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // The redeem button is still disabled | // The redeem button is still disabled | ||||
| expect(redeemButton).toBeDisabled(); | expect(redeemButton).toBeDisabled(); | ||||
| // OK we redeem more than dust | // OK we redeem more than dust | ||||
| await userEvent.clear(screen.getByPlaceholderText('Total qty')); | await userEvent.clear(screen.getByPlaceholderText('Total qty')); | ||||
| await userEvent.type(screen.getByPlaceholderText('Total qty'), '10'); | await userEvent.type(screen.getByPlaceholderText('Total qty'), '10'); | ||||
| expect(screen.getByPlaceholderText('Total qty')).toHaveValue(10); | expect(screen.getByPlaceholderText('Total qty')).toHaveValue(10); | ||||
| // The redeem button is now enabled | // The redeem button is now enabled | ||||
| expect(redeemButton).toBeEnabled(); | expect(redeemButton).toBeEnabled(); | ||||
| // Redeem | // Redeem | ||||
| await userEvent.click(redeemButton); | await userEvent.click(redeemButton); | ||||
| // Async as we must wait for multiple partials | // Async as we must wait for multiple partials | ||||
| expect( | expect( | ||||
| await screen.findByText('Redeem $FIRMA for XEC?'), | await screen.findByText('Redeem $FIRMA ALPHA for XEC?'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Offered qty (actual, calculated from AgoraOffer) | // Offered qty (actual, calculated from AgoraOffer) | ||||
| const actualOfferedQty = '10.0000'; | const actualOfferedQty = '10.0000'; | ||||
| expect( | expect( | ||||
| screen.getByText(`${actualOfferedQty} $FIRMA`), | screen.getByText(`${actualOfferedQty} $${FIRMA_DISPLAY_TICKER}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Actual price calculated from AgoraOffer | // Actual price calculated from AgoraOffer | ||||
| const actualPricePerTokenForMinBuy = '40,000.00 XEC'; | const actualPricePerTokenForMinBuy = '40,000.00 XEC'; | ||||
| // We see the price once; it is not previewed as we need to calculate it before we | // We see the price once; it is not previewed as we need to calculate it before we | ||||
| // show the modal | // show the modal | ||||
| expect( | expect( | ||||
| screen.getByText(actualPricePerTokenForMinBuy), | screen.getByText(actualPricePerTokenForMinBuy), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // We see the full receive XEC amount | // We see the full receive XEC amount | ||||
| expect(screen.getByText('You receive:')).toBeInTheDocument(); | expect(screen.getByText('You receive:')).toBeInTheDocument(); | ||||
| expect(screen.getByText('400,000.01 XEC')).toBeInTheDocument(); | expect(screen.getByText('400,000.01 XEC')).toBeInTheDocument(); | ||||
| // We can cancel and not create this listing | // We can cancel and not create this listing | ||||
| await userEvent.click(screen.getByText('Cancel')); | await userEvent.click(screen.getByText('Cancel')); | ||||
| // The confirmation modal is gone | // The confirmation modal is gone | ||||
| expect( | expect( | ||||
| screen.queryByText('Redeem $FIRMA for XEC?'), | screen.queryByText('Redeem $FIRMA ALPHA for XEC?'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // We change our mind and list it | // We change our mind and list it | ||||
| await userEvent.click(redeemButton); | await userEvent.click(redeemButton); | ||||
| expect( | expect( | ||||
| await screen.findByText('Redeem $FIRMA for XEC?'), | await screen.findByText('Redeem $FIRMA ALPHA for XEC?'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // We see the expected toast notification for the successful listing tx | // We see the expected toast notification for the successful listing tx | ||||
| expect( | expect( | ||||
| await screen.findByText( | await screen.findByText( | ||||
| `${actualOfferedQty} Firma listed for ${actualPricePerTokenForMinBuy} per token`, | `${actualOfferedQty} ${FIRMA_DISPLAY_NAME} listed for ${actualPricePerTokenForMinBuy} per token`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| }); | }); | ||||
| it('FIRMA redeem is disabled if the hot wallet cannot cover redeem amount', async () => { | it('FIRMA redeem is disabled if the hot wallet cannot cover redeem amount', async () => { | ||||
| // Mock Math.random() | // Mock Math.random() | ||||
| jest.spyOn(global.Math, 'random').mockReturnValue(0.5); // set a fixed value | jest.spyOn(global.Math, 'random').mockReturnValue(0.5); // set a fixed value | ||||
| // Mock a bid price | // Mock a bid price | ||||
| Show All 32 Lines | it('FIRMA redeem is disabled if the hot wallet cannot cover redeem amount', async () => { | ||||
| <CashtabTestWrapper | <CashtabTestWrapper | ||||
| chronik={mockedChronik} | chronik={mockedChronik} | ||||
| ecc={ecc} | ecc={ecc} | ||||
| agora={agora} | agora={agora} | ||||
| route={`/send-token/${FIRMA.tokenId}`} | route={`/send-token/${FIRMA.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = FIRMA.token.genesisInfo; | const { tokenName } = { tokenName: FIRMA_DISPLAY_NAME }; | ||||
| // Wait for element to get token info and load | // Wait for element to get token info and load | ||||
| expect( | expect( | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect( | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | await screen.findByRole('button', { name: '+ Buy' }), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Click Redeem to show the redeem form | // Click Redeem to show the redeem form | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { name: '− Redeem' }), | await screen.findByRole('button', { name: '− Redeem' }), | ||||
| ); | ); | ||||
| // The redeem button is disabled on load | // The redeem button is disabled on load | ||||
| const redeemButton = await screen.findByRole('button', { | const redeemButton = await screen.findByRole('button', { | ||||
| name: /Redeem FIRMA for XEC/, | name: /Redeem FIRMA ALPHA for XEC/, | ||||
| }); | }); | ||||
| await waitFor(() => expect(redeemButton).toBeDisabled()); | await waitFor(() => expect(redeemButton).toBeDisabled()); | ||||
| // We do not see a price input | // We do not see a price input | ||||
| expect( | expect( | ||||
| screen.queryByPlaceholderText('Enter list price (per token)'), | screen.queryByPlaceholderText('Enter list price (per token)'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| Show All 9 Lines | it('FIRMA redeem is disabled if the hot wallet cannot cover redeem amount', async () => { | ||||
| // The redeem button is now enabled | // The redeem button is now enabled | ||||
| expect(redeemButton).toBeEnabled(); | expect(redeemButton).toBeEnabled(); | ||||
| // Redeem | // Redeem | ||||
| await userEvent.click(redeemButton); | await userEvent.click(redeemButton); | ||||
| // Async as we must wait for multiple partials | // Async as we must wait for multiple partials | ||||
| expect( | expect( | ||||
| await screen.findByText('Redeem $FIRMA for XEC?'), | await screen.findByText('Redeem $FIRMA ALPHA for XEC?'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Offered qty (actual, calculated from AgoraOffer) | // Offered qty (actual, calculated from AgoraOffer) | ||||
| const actualOfferedQty = '10.0000'; | const actualOfferedQty = '10.0000'; | ||||
| expect( | expect( | ||||
| screen.getByText(`${actualOfferedQty} $FIRMA`), | screen.getByText(`${actualOfferedQty} $${FIRMA_DISPLAY_TICKER}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Actual price calculated from AgoraOffer | // Actual price calculated from AgoraOffer | ||||
| const actualPricePerTokenForMinBuy = '40,000.00 XEC'; | const actualPricePerTokenForMinBuy = '40,000.00 XEC'; | ||||
| // We see the price once; it is not previewed as we need to calculate it before we | // We see the price once; it is not previewed as we need to calculate it before we | ||||
| // show the modal | // show the modal | ||||
| expect( | expect( | ||||
| screen.getByText(actualPricePerTokenForMinBuy), | screen.getByText(actualPricePerTokenForMinBuy), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // We see the full receive XEC amount | // We see the full receive XEC amount | ||||
| expect(screen.getByText('You receive:')).toBeInTheDocument(); | expect(screen.getByText('You receive:')).toBeInTheDocument(); | ||||
| expect(screen.getByText('400,000.01 XEC')).toBeInTheDocument(); | expect(screen.getByText('400,000.01 XEC')).toBeInTheDocument(); | ||||
| // We see an alert as the hot wallet cannot cover this redemption | // We see an alert as the hot wallet cannot cover this redemption | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| 'Hot wallet balance cannot support redemptions of more than 1,000.00 XEC worth of $FIRMA. Top-up pending.', | `Hot wallet balance cannot support redemptions of more than 1,000.00 XEC worth of $${FIRMA_DISPLAY_TICKER}. Top-up pending.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Redeem is disabled | // Redeem is disabled | ||||
| const redeemBtnModal = screen.getByRole('button', { | const redeemBtnModal = screen.getByRole('button', { | ||||
| name: /OK/, | name: /OK/, | ||||
| }); | }); | ||||
| expect(redeemBtnModal).toBeDisabled(); | expect(redeemBtnModal).toBeDisabled(); | ||||
| Show All 19 Lines | it('We show expected error if we are unable to get FIRMA bid price from API', async () => { | ||||
| <CashtabTestWrapper | <CashtabTestWrapper | ||||
| chronik={mockedChronik} | chronik={mockedChronik} | ||||
| ecc={ecc} | ecc={ecc} | ||||
| agora={agora} | agora={agora} | ||||
| route={`/token/${FIRMA.tokenId}`} | route={`/token/${FIRMA.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = FIRMA.token.genesisInfo; | const { tokenName } = { tokenName: FIRMA_DISPLAY_NAME }; | ||||
| // Wait for element to get token info and load | // Wait for element to get token info and load | ||||
| expect( | expect( | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | await screen.findByAltText(`icon for ${FIRMA.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect( | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | await screen.findByRole('button', { name: '+ Buy' }), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Click Redeem to show the redeem form | // Click Redeem to show the redeem form | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { name: '− Redeem' }), | await screen.findByRole('button', { name: '− Redeem' }), | ||||
| ); | ); | ||||
| // The redeem button is disabled on load | // The redeem button is disabled on load | ||||
| const redeemButton = await screen.findByRole('button', { | const redeemButton = await screen.findByRole('button', { | ||||
| name: /Redeem FIRMA for XEC/, | name: /Redeem FIRMA ALPHA for XEC/, | ||||
Fabien: should be Firma Alpha ? | |||||
| }); | }); | ||||
| expect(redeemButton).toBeDisabled(); | expect(redeemButton).toBeDisabled(); | ||||
| // We do not see a price input | // We do not see a price input | ||||
| expect( | expect( | ||||
| screen.queryByPlaceholderText('Enter list price (per token)'), | screen.queryByPlaceholderText('Enter list price (per token)'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // We do not see a min qty input | // We do not see a min qty input | ||||
| expect( | expect( | ||||
| screen.queryByPlaceholderText('Min qty'), | screen.queryByPlaceholderText('Min qty'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // Enter amount to redeem | // Enter amount to redeem | ||||
| await userEvent.type(screen.getByPlaceholderText('Total qty'), '0.009'); | await userEvent.type(screen.getByPlaceholderText('Total qty'), '0.009'); | ||||
| // This is below firma min redemption so we get an error | // This is below firma min redemption so we get an error | ||||
| expect( | expect( | ||||
| screen.getByText('Cannot redeem less than 0.01 FIRMA'), | screen.getByText('Cannot redeem less than 0.01 FIRMA ALPHA'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // The redeem button is still disabled | // The redeem button is still disabled | ||||
| expect(redeemButton).toBeDisabled(); | expect(redeemButton).toBeDisabled(); | ||||
| // OK we redeem more than dust | // OK we redeem more than dust | ||||
| await userEvent.clear(screen.getByPlaceholderText('Total qty')); | await userEvent.clear(screen.getByPlaceholderText('Total qty')); | ||||
| ▲ Show 20 Lines • Show All 325 Lines • ▼ Show 20 Lines | it('We do not allow users to list FIRMA below the bid price', async () => { | ||||
| <CashtabTestWrapper | <CashtabTestWrapper | ||||
| chronik={mockedChronik} | chronik={mockedChronik} | ||||
| ecc={ecc} | ecc={ecc} | ||||
| agora={agora} | agora={agora} | ||||
| route={`/send-token/${FIRMA.tokenId}`} | route={`/send-token/${FIRMA.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = FIRMA.token.genesisInfo; | const { tokenName } = { tokenName: FIRMA_DISPLAY_NAME }; | ||||
| // Wait for element to get token info and load | // Wait for element to get token info and load | ||||
| expect( | expect( | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Firma token icon is rendered | // Firma token icon is rendered | ||||
| expect( | expect( | ||||
| Show All 24 Lines | it('We do not allow users to list FIRMA below the bid price', async () => { | ||||
| // Make sure the min buy is correct | // Make sure the min buy is correct | ||||
| const minQtyInput = screen.getByPlaceholderText('Min qty'); | const minQtyInput = screen.getByPlaceholderText('Min qty'); | ||||
| await userEvent.clear(minQtyInput); | await userEvent.clear(minQtyInput); | ||||
| await userEvent.type(minQtyInput, '1'); | await userEvent.type(minQtyInput, '1'); | ||||
| // The redeem button is disabled on load | // The redeem button is disabled on load | ||||
| const listButton = await screen.findByRole('button', { | const listButton = await screen.findByRole('button', { | ||||
| name: /List Firma/, | name: /List Firma Alpha/, | ||||
| }); | }); | ||||
| // try to list | // try to list | ||||
| await userEvent.click(listButton); | await userEvent.click(listButton); | ||||
| // Async as we must wait for multiple partials | // Async as we must wait for multiple partials | ||||
| expect(await screen.findByText('List FIRMA?')).toBeInTheDocument(); | expect( | ||||
| await screen.findByText('List FIRMA ALPHA?'), | |||||
| ).toBeInTheDocument(); | |||||
| // We see a warning msg about the poorly selected price | // We see a warning msg about the poorly selected price | ||||
| expect( | expect( | ||||
| await screen.findByText( | await screen.findByText( | ||||
| `⚠️ Warning: You are listing FIRMA for 1,000 XEC per token, which is below FIRMA's current buy price of 40,000 XEC per token. You should redeem FIRMA instead to get the best price.`, | `⚠️ Warning: You are listing FIRMA ALPHA for 1,000 XEC per token, which is below FIRMA ALPHA's current buy price of 40,000 XEC per token. You should redeem FIRMA ALPHA instead to get the best price.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // The "OK" button is disabled | // The "OK" button is disabled | ||||
| expect(screen.getByText('OK')).toBeDisabled(); | expect(screen.getByText('OK')).toBeDisabled(); | ||||
| }); | }); | ||||
| }); | }); | ||||
should be Firma Alpha ?