Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/components/Etokens/__tests__/TokenActions.test.js
| Show First 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | it('SLP1 fixed supply token', async () => { | ||||
| const { tokenName } = slp1FixedMocks.token.genesisInfo; | const { tokenName } = slp1FixedMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| `SLP 1 fungible token. Token may be of fixed supply if no mint batons exist. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places.`, | `SLP 1 fungible token. Token may be of fixed supply if no mint batons exist. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The supply is correctly rendered as fixed | // The supply is correctly rendered as fixed | ||||
| expect( | expect( | ||||
| screen.getByText('2,999,998,798.000000000 (fixed)'), | screen.getByText('2,999,998,798.000000000 (fixed)'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available with Buy and Sell buttons | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| // The sell switch is turned on by default | ).toBeInTheDocument(); | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toHaveProperty( | expect( | ||||
| 'checked', | screen.getByRole('button', { name: '− Sell' }), | ||||
| true, | ).toBeInTheDocument(); | ||||
| ); | |||||
| // The send switch is present | |||||
| expect(screen.getByTitle('Toggle Send')).toBeInTheDocument(); | |||||
| // The Airdrop switch is present | |||||
| expect(screen.getByTitle('Toggle Airdrop')).toBeInTheDocument(); | |||||
| // The Burn switch is present | // More dropdown contains Send, Airdrop, Burn | ||||
| expect(screen.getByTitle('Toggle Burn')).toBeInTheDocument(); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| expect( | |||||
| screen.getByRole('button', { name: 'Send' }), | |||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Burn' }), | |||||
| ).toBeInTheDocument(); | |||||
| // The Mint switch is not rendered | // The Mint option is not in the dropdown for fixed supply | ||||
| expect(screen.queryByTitle('Toggle Mint')).not.toBeInTheDocument(); | expect( | ||||
| screen.queryByRole('button', { name: 'Mint' }), | |||||
| ).not.toBeInTheDocument(); | |||||
| }); | }); | ||||
| it('SLP1 variable supply token with mint baton', async () => { | it('SLP1 variable supply token with mint baton', async () => { | ||||
| render( | render( | ||||
| <CashtabTestWrapper | <CashtabTestWrapper | ||||
| chronik={mockedChronik} | chronik={mockedChronik} | ||||
| agora={mockAgora} | agora={mockAgora} | ||||
| ecc={ecc} | ecc={ecc} | ||||
| route={`/send-token/${slp1VarMocks.tokenId}`} | route={`/send-token/${slp1VarMocks.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = slp1VarMocks.token.genesisInfo; | const { tokenName } = slp1VarMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| `SLP 1 fungible token. Token may be of fixed supply if no mint batons exist. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places.`, | `SLP 1 fungible token. Token may be of fixed supply if no mint batons exist. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The supply is correctly rendered as fixed | // The supply is correctly rendered as variable | ||||
| expect( | expect( | ||||
| screen.getByText('18,446,744,073.709551615 (var.)'), | screen.getByText('18,446,744,073.709551615 (var.)'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available with Buy and Sell buttons | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| // The sell switch is turned on by default | ).toBeInTheDocument(); | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toHaveProperty( | expect( | ||||
| 'checked', | screen.getByRole('button', { name: '− Sell' }), | ||||
| true, | ).toBeInTheDocument(); | ||||
| ); | |||||
| // The send switch is present | |||||
| expect(screen.getByTitle('Toggle Send')).toBeInTheDocument(); | |||||
| // The Airdrop switch is present | |||||
| expect(screen.getByTitle('Toggle Airdrop')).toBeInTheDocument(); | |||||
| // The Burn switch is present | |||||
| expect(screen.getByTitle('Toggle Burn')).toBeInTheDocument(); | |||||
| // The Mint switch is present and not disabled | // More dropdown contains Send, Airdrop, Burn, Mint | ||||
| expect(screen.getByTitle('Toggle Mint')).toHaveProperty( | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| 'disabled', | expect( | ||||
| false, | screen.getByRole('button', { name: 'Send' }), | ||||
| ); | ).toBeInTheDocument(); | ||||
| expect( | |||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Burn' }), | |||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Mint' }), | |||||
| ).toBeInTheDocument(); | |||||
| }); | }); | ||||
| it('We can list an SLP1 fungible token', async () => { | it('We can list an SLP1 fungible token', 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 | ||||
| // SLP1 ad prep | // SLP1 ad prep | ||||
| const adPrepHex = | const adPrepHex = | ||||
| '0200000002ef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441c8af21dd92d03eafdbb1e3aff93e297f373b5f3dbc9b9bf0b8281aeb1bd679bae2d8f9d8eb6655b6b6754cc0683a0fa9234d6242c2f3a4503bf682aa30af2ec64121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff666de5d5852807a13612b6ea0373643266d435822daeb39c29e5d4b67e893cda010000006441774b63b6872e525ffd110f95fe72f9766b0d1a348f995ed25cc2dd82118ad552b438aee61520ec4637901c6a40e1362ff349ad65bd545e6de7762eb49d21cab94121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001010453454e442020a0b9337a78603c6681ed2bc541593375535dcd9979196620ce71f233f2f6f80800000019d81d9600060500000000000017a91472065f43eb5358b84763ecf40440d0fc9914e6c887a4300f00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; | '0200000002ef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441c8af21dd92d03eafdbb1e3aff93e297f373b5f3dbc9b9bf0b8281aeb1bd679bae2d8f9d8eb6655b6b6754cc0683a0fa9234d6242c2f3a4503bf682aa30af2ec64121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff666de5d5852807a13612b6ea0373643266d435822daeb39c29e5d4b67e893cda010000006441774b63b6872e525ffd110f95fe72f9766b0d1a348f995ed25cc2dd82118ad552b438aee61520ec4637901c6a40e1362ff349ad65bd545e6de7762eb49d21cab94121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001010453454e442020a0b9337a78603c6681ed2bc541593375535dcd9979196620ce71f233f2f6f80800000019d81d9600060500000000000017a91472065f43eb5358b84763ecf40440d0fc9914e6c887a4300f00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; | ||||
| Show All 27 Lines | it('We can list an SLP1 fungible token', async () => { | ||||
| agora={agora} | agora={agora} | ||||
| route={`/send-token/${slp1FixedMocks.tokenId}`} | route={`/send-token/${slp1FixedMocks.tokenId}`} | ||||
| />, | />, | ||||
| ); | ); | ||||
| const { tokenName } = slp1FixedMocks.token.genesisInfo; | const { tokenName } = slp1FixedMocks.token.genesisInfo; | ||||
| // Wait for element to get token info and load | // Wait for element to get token info and load | ||||
| expect(await screen.findAllByText(new RegExp(tokenName))).toHaveLength( | expect( | ||||
| 3, | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ); | ).toBeInTheDocument(); | ||||
| // Token image is rendered | // Token image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${slp1FixedMocks.tokenId}`), | screen.getByAltText(`icon for ${slp1FixedMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available - click Sell to show the list form | ||||
| expect(await screen.findByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '− Sell' }), | |||||
| // On load, default action for SLP is to list it | ).toBeInTheDocument(); | ||||
| expect(await screen.findByTitle('Toggle Sell Token')).toBeEnabled(); | await userEvent.click(screen.getByRole('button', { name: '− Sell' })); | ||||
| // The list button is disabled on load | // The list button is disabled on load | ||||
| const listButton = await screen.findByRole('button', { | const listButton = await screen.findByRole('button', { | ||||
| name: /List Vespene Gas/, | name: /List Vespene Gas/, | ||||
| }); | }); | ||||
| await waitFor(() => expect(listButton).toBeDisabled()); | await waitFor(() => expect(listButton).toBeDisabled()); | ||||
| // The price input is disabled until qty values are entered | // The price input is disabled until qty values are entered | ||||
| const priceInput = screen.getByPlaceholderText( | const priceInput = screen.getByPlaceholderText( | ||||
| 'Enter list price (per token)', | 'Enter list price (per token)', | ||||
| ); | ); | ||||
| expect(priceInput).toBeDisabled(); | expect(priceInput).toBeDisabled(); | ||||
| const minQtyInput = screen.getByPlaceholderText('Min qty'); | const minQtyInput = screen.getByPlaceholderText('Min qty'); | ||||
| // Min qty input is disabled before we enter offered qty | // Min qty input is disabled before we enter offered qty | ||||
| expect(minQtyInput).toBeDisabled(); | expect(minQtyInput).toBeDisabled(); | ||||
| // Enter token balance as offered qty | // Enter token balance as offered qty (Slider uses name as placeholder when no label) | ||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '111'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '111', | |||||
| ); | |||||
| // The price input is no longer disabled | // The price input is no longer disabled | ||||
| expect(priceInput).toBeEnabled(); | expect(priceInput).toBeEnabled(); | ||||
| // We see expected error msg if we try to list the token at a price where the min buy would cost less than dust | // We see expected error msg if we try to list the token at a price where the min buy would cost less than dust | ||||
| await userEvent.type(priceInput, '0.001'); | await userEvent.type(priceInput, '0.001'); | ||||
| // The min qty input updates automatically when price is set to reflect the actual min qty | // The min qty input updates automatically when price is set to reflect the actual min qty | ||||
| ▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Lines | it('We can correctly render an SLP1 NFT Parent token with no ready NFT Mint inputs, then mint an NFT as ecash-wallet will automatically prepare them', async () => { | ||||
| ).not.toBeInTheDocument(), | ).not.toBeInTheDocument(), | ||||
| ); | ); | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The supply is correctly rendered | // The supply is correctly rendered | ||||
| expect(screen.getByText('100 (var.)')).toBeInTheDocument(); | expect(screen.getByText('100 (var.)')).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available - open dropdown for Mint NFT | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect(screen.getByRole('button', { name: '⋯' })).toBeInTheDocument(); | ||||
| await userEvent.click(screen.getByRole('button', { name: '⋯' })); | |||||
| // The mint NFT option is available | // The Mint NFT option is available and enabled | ||||
| expect(screen.getByTitle('Toggle Mint NFT')).toBeInTheDocument(); | const mintNftOption = screen.getByRole('button', { name: 'Mint NFT' }); | ||||
| expect(mintNftOption).toBeInTheDocument(); | |||||
| expect(mintNftOption).toBeEnabled(); | |||||
| // The mint NFT option is enabled even if there are no qty-1 utxos aka mint inputs | // The Airdrop action is available in the dropdown | ||||
| expect(screen.getByTitle('Toggle Mint NFT')).toBeEnabled(); | expect( | ||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| // The Airdrop action is available | // The Burn action is NOT available for NFT parent | ||||
| expect(screen.getByTitle('Toggle Airdrop')).toBeInTheDocument(); | expect( | ||||
| screen.queryByRole('button', { name: 'Burn' }), | |||||
| ).not.toBeInTheDocument(); | |||||
| // The Burn action is NOT available | // Click Mint NFT to show the mint form | ||||
| expect(screen.queryByTitle('Toggle Burn')).not.toBeInTheDocument(); | await userEvent.click(mintNftOption); | ||||
| // We can mint an NFT if we give it a name and a ticker | // We can mint an NFT if we give it a name and a ticker | ||||
| await userEvent.type( | await userEvent.type( | ||||
| await screen.findByPlaceholderText('Enter a name for your NFT'), | await screen.findByPlaceholderText('Enter a name for your NFT'), | ||||
| 'Bitcoin ABC', | 'Bitcoin ABC', | ||||
| ); | ); | ||||
| // The mint button is disabled as the user has not entered a ticker | // The mint button is disabled as the user has not entered a ticker | ||||
| ▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | it('We can correctly render an SLP1 NFT Parent token with NFT Mint inputs, then mint an NFT', async () => { | ||||
| ).not.toBeInTheDocument(), | ).not.toBeInTheDocument(), | ||||
| ); | ); | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The supply is correctly rendered | // The supply is correctly rendered | ||||
| expect(screen.getByText('100 (var.)')).toBeInTheDocument(); | expect(screen.getByText('100 (var.)')).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available - open dropdown for Mint NFT | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| // The mint NFT option is available | |||||
| expect(screen.getByTitle('Toggle Mint NFT')).toBeInTheDocument(); | |||||
| // The mint NFT option is NOT disabled as we have a single mint input | // The mint NFT option is available and NOT disabled | ||||
| expect(screen.getByTitle('Toggle Mint NFT')).toBeEnabled(); | const mintNftOption = screen.getByRole('button', { name: 'Mint NFT' }); | ||||
| expect(mintNftOption).toBeInTheDocument(); | |||||
| expect(mintNftOption).toBeEnabled(); | |||||
| // The mint NFT switch label does not include the disabled explanation | // The mint NFT switch label does not include the disabled explanation | ||||
| expect( | expect( | ||||
| screen.queryByText('(no NFT mint inputs)'), | screen.queryByText('(no NFT mint inputs)'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // The Airdrop action is available | // The Airdrop action is available in the dropdown | ||||
| expect(screen.getByTitle('Toggle Airdrop')).toBeInTheDocument(); | expect( | ||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| // The Burn action is NOT available | // The Burn action is NOT available for NFT parent | ||||
| expect(screen.queryByTitle('Toggle Burn')).not.toBeInTheDocument(); | expect( | ||||
| screen.queryByRole('button', { name: 'Burn' }), | |||||
| ).not.toBeInTheDocument(); | |||||
| // Click Mint NFT to show the mint form (or form may already be visible from default) | |||||
| await userEvent.click(mintNftOption); | |||||
| // We can mint an NFT if we give it a name and a ticker | // We can mint an NFT if we give it a name and a ticker | ||||
| await userEvent.type( | await userEvent.type( | ||||
| await screen.findByPlaceholderText('Enter a name for your NFT'), | await screen.findByPlaceholderText('Enter a name for your NFT'), | ||||
| 'Bitcoin ABC', | 'Bitcoin ABC', | ||||
| ); | ); | ||||
| // The mint button is disabled as the user has not entered a ticker | // The mint button is disabled as the user has not entered a ticker | ||||
| ▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | it('We can render an SLP1 NFT Parent token with a minted NFT in its collection', async () => { | ||||
| ).not.toBeInTheDocument(), | ).not.toBeInTheDocument(), | ||||
| ); | ); | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | `The parent tokens for an NFT collection. Can be used to mint NFTs. No decimal places. The supply of this token is the potential quantity of NFTs which could be minted. If no mint batons exist, the supply is fixed.`, | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The wallet balance of this token is correctly rendered | // The wallet balance of this token is correctly rendered | ||||
| expect(screen.getByText('1 (fixed)')).toBeInTheDocument(); | expect(screen.getByText('1 (fixed)')).toBeInTheDocument(); | ||||
| // Token actions are available | // Token action bar is available - open dropdown | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| // The mint NFT option is available | |||||
| expect(screen.getByTitle('Toggle Mint NFT')).toBeInTheDocument(); | |||||
| // The mint NFT option is NOT disabled as we have a single mint input | // The mint NFT option is available and NOT disabled | ||||
| expect(screen.getByTitle('Toggle Mint NFT')).toHaveProperty( | const mintNftOption = screen.getByRole('button', { name: 'Mint NFT' }); | ||||
| 'disabled', | expect(mintNftOption).toBeInTheDocument(); | ||||
| false, | expect(mintNftOption).toHaveProperty('disabled', false); | ||||
| ); | |||||
| // The mint NFT switch label does not include the disabled explanation | // The mint NFT switch label does not include the disabled explanation | ||||
| expect( | expect( | ||||
| screen.queryByText('(no NFT mint inputs)'), | screen.queryByText('(no NFT mint inputs)'), | ||||
| ).not.toBeInTheDocument(); | ).not.toBeInTheDocument(); | ||||
| // The Airdrop action is available | // The Airdrop action is available in the dropdown | ||||
| expect(screen.getByTitle('Toggle Airdrop')).toBeInTheDocument(); | expect( | ||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| // The Burn action is NOT available | // The Burn action is NOT available for NFT parent | ||||
| expect(screen.queryByTitle('Toggle Burn')).not.toBeInTheDocument(); | expect( | ||||
| screen.queryByRole('button', { name: 'Burn' }), | |||||
| ).not.toBeInTheDocument(); | |||||
| // A child NFT is rendered | // A child NFT is rendered | ||||
| expect(screen.getByText('NFTs in this Collection')).toBeInTheDocument(); | expect(screen.getByText('NFTs in this Collection')).toBeInTheDocument(); | ||||
| // NFT image is rendered | // NFT image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | it('We can list an SLP1 NFT', async () => { | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // NFT image is rendered | // NFT image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| Show All 9 Lines | it('We can list an SLP1 NFT', async () => { | ||||
| expect(screen.getByText('Gordon Chen')).toBeInTheDocument(); | expect(screen.getByText('Gordon Chen')).toBeInTheDocument(); | ||||
| // We see what collection this NFT is from | // We see what collection this NFT is from | ||||
| expect(screen.getByText(/NFT from collection/)).toBeInTheDocument(); | expect(screen.getByText(/NFT from collection/)).toBeInTheDocument(); | ||||
| expect( | expect( | ||||
| screen.getByText('The Four Half-Coins of Jin-qua'), | screen.getByText('The Four Half-Coins of Jin-qua'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available for NFTs | // Click Sell to show the NFT list form | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | await userEvent.click(screen.getByRole('button', { name: '− Sell' })); | ||||
| // On load, default action for NFT is to list it | |||||
| expect(screen.getByTitle('Toggle Sell NFT')).toBeChecked(); | |||||
| // We see a price input field for listing this NFT | // We see a price input field for listing this NFT | ||||
| const priceInput = screen.getByPlaceholderText('Enter NFT list price'); | const priceInput = screen.getByPlaceholderText('Enter NFT list price'); | ||||
| expect(priceInput).toBeInTheDocument(); | expect(priceInput).toBeInTheDocument(); | ||||
| // We see expected error msg if we try to list the NFT for less than dust | // We see expected error msg if we try to list the NFT for less than dust | ||||
| await userEvent.type(priceInput, '5.45'); | await userEvent.type(priceInput, '5.45'); | ||||
| expect( | expect( | ||||
| ▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | it('We can send an SLP1 NFT', async () => { | ||||
| const { tokenName } = slp1NftChildMocks.token.genesisInfo; | const { tokenName } = slp1NftChildMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // On load, default action for NFT is to list it | // Click Sell to show the list form (default is Buy) | ||||
| const sellActionSwitch = screen.getByTitle('Toggle Sell NFT'); | await userEvent.click( | ||||
| await waitFor(() => expect(sellActionSwitch).toBeChecked()); | await screen.findByRole('button', { name: '− Sell' }), | ||||
| ); | |||||
| // Sending is disabled | |||||
| const sendActionSwitch = screen.getByTitle('Toggle Send'); | |||||
| expect(sendActionSwitch).not.toBeChecked(); | |||||
| // When we enable Sending, Selling is disabled, and Sending is enabled | |||||
| await userEvent.click(sendActionSwitch); | |||||
| expect(sendActionSwitch).toBeChecked(); | |||||
| expect(sellActionSwitch).not.toBeChecked(); | |||||
| // We see an Address input | // We see the sell form (price input for listing) | ||||
| expect( | |||||
| screen.getByPlaceholderText('Enter NFT list price'), | |||||
| ).toBeInTheDocument(); | |||||
| // Switch to Send - open dropdown and click Send | |||||
| await userEvent.click(screen.getByRole('button', { name: '⋯' })); | |||||
| await userEvent.click(screen.getByRole('button', { name: 'Send' })); | |||||
| // We see an Address input (send form) | |||||
| const addrInput = screen.getByPlaceholderText('Address'); | const addrInput = screen.getByPlaceholderText('Address'); | ||||
| expect(addrInput).toBeInTheDocument(); | expect(addrInput).toBeInTheDocument(); | ||||
| // Send button is disabled before address entry | // Send button is disabled before address entry | ||||
| const sendButton = screen.getByRole('button', { | const sendButton = screen.getByRole('button', { | ||||
| name: /Send GC/, | name: /Send GC/, | ||||
| }); | }); | ||||
| expect(sendButton).toBeDisabled(); | expect(sendButton).toBeDisabled(); | ||||
| ▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | it('SLP1 NFT page will update cashtab token cache for the NFT if it does not include groupTokenId, and for its parent if it is not in cache', async () => { | ||||
| (await screen.findAllByText(new RegExp(tokenName)))[0], | (await screen.findAllByText(new RegExp(tokenName)))[0], | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // NFT image is rendered | // NFT image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | screen.getByAltText(`icon for ${slp1NftChildMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| Show All 10 Lines | it('SLP1 NFT page will update cashtab token cache for the NFT if it does not include groupTokenId, and for its parent if it is not in cache', async () => { | ||||
| // We see what collection this NFT is from | // We see what collection this NFT is from | ||||
| expect(screen.getByText(/NFT from collection/)).toBeInTheDocument(); | expect(screen.getByText(/NFT from collection/)).toBeInTheDocument(); | ||||
| expect( | expect( | ||||
| screen.getByText('The Four Half-Coins of Jin-qua'), | screen.getByText('The Four Half-Coins of Jin-qua'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available for NFTs | // Token actions are available for NFTs | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // Click Sell to show the NFT list form | |||||
| await userEvent.click(screen.getByRole('button', { name: '− Sell' })); | |||||
| // On load, the default action for an NFT is to list it | |||||
| const nftListInput = screen.getByPlaceholderText( | const nftListInput = screen.getByPlaceholderText( | ||||
| 'Enter NFT list price', | 'Enter NFT list price', | ||||
| ); | ); | ||||
| expect(nftListInput).toBeInTheDocument(); | expect(nftListInput).toBeInTheDocument(); | ||||
| }); | }); | ||||
| it('We show an agora query error if we cannot get active offers for an NFT token id', async () => { | it('We show an agora query error if we cannot get active offers for an NFT token id', async () => { | ||||
| const heismanNftTokenId = heismanNftOneOffer.token.tokenId; | const heismanNftTokenId = heismanNftOneOffer.token.tokenId; | ||||
| ▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | it('ALP token', async () => { | ||||
| const { tokenName } = alpMocks.token.genesisInfo; | const { tokenName } = alpMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Expand Token Details to access the info button | |||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| // We can click an info icon to learn more about this token type | // We can click an info icon to learn more about this token type | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { | await screen.findByRole('button', { | ||||
| name: 'Click for more info about this token type', | name: 'Click for more info about this token type', | ||||
| }), | }), | ||||
| ); | ); | ||||
| expect( | expect( | ||||
| screen.getByText( | screen.getByText( | ||||
| 'ALP v1 fungible token. Token may be of fixed or variable supply. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places. ALP tokens use EMPP technology, which supports more token actions compared to SLP and more complex combinations of token and app actions. ALP token txs may have up to 127 outputs, though current OP_RETURN size de facto limits a single tx to 29 outputs.', | 'ALP v1 fungible token. Token may be of fixed or variable supply. If you have a mint baton, you can mint more of this token at any time. May have up to 9 decimal places. ALP tokens use EMPP technology, which supports more token actions compared to SLP and more complex combinations of token and app actions. ALP token txs may have up to 127 outputs, though current OP_RETURN size de facto limits a single tx to 29 outputs.', | ||||
| ), | ), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Close out of the info modal | // Close out of the info modal | ||||
| await userEvent.click(screen.getByText('OK')); | await userEvent.click(screen.getByText('OK')); | ||||
| // The supply is correctly rendered | // The supply is correctly rendered (expand already done for info button) | ||||
| expect(screen.getByText('111,367.0000 (var.)')).toBeInTheDocument(); | expect(screen.getByText(/111,367\.\d+ \(var\.\)/)).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // We can list, which is also the default action | // We can list (Sell button is enabled) | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toBeEnabled(); | expect(screen.getByRole('button', { name: '− Sell' })).toBeEnabled(); | ||||
| // We can send | // We can send, airdrop, burn via the more dropdown | ||||
| expect(screen.getByTitle('Toggle Send')).toBeInTheDocument(); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| // We can burn | expect( | ||||
| expect(screen.getByTitle('Toggle Burn')).toBeInTheDocument(); | screen.getByRole('button', { name: 'Send' }), | ||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Airdrop' }), | |||||
| ).toBeInTheDocument(); | |||||
| expect( | |||||
| screen.getByRole('button', { name: 'Burn' }), | |||||
| ).toBeInTheDocument(); | |||||
| // Because we do not have the mint baton for this token, the Mint action is NOT available | // Because we do not have the mint baton for this token, the Mint action is NOT available | ||||
| expect(screen.queryByTitle('Toggle Mint')).not.toBeInTheDocument(); | expect( | ||||
| screen.queryByRole('button', { name: 'Mint' }), | |||||
| ).not.toBeInTheDocument(); | |||||
| }); | }); | ||||
| it('We can send an ALP token', async () => { | it('We can send an ALP token', async () => { | ||||
| const mockedAgora = new MockAgora(); | const mockedAgora = new MockAgora(); | ||||
| mockedAgora.setOfferedGroupTokenIds([]); | mockedAgora.setOfferedGroupTokenIds([]); | ||||
| // It's not listed yet | // It's not listed yet | ||||
| mockedAgora.setActiveOffersByTokenId(alpMocks.tokenId, []); | mockedAgora.setActiveOffersByTokenId(alpMocks.tokenId, []); | ||||
| Show All 25 Lines | it('We can send an ALP token', async () => { | ||||
| const { tokenName } = alpMocks.token.genesisInfo; | const { tokenName } = alpMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Wait for supply and actions to load | // Expand Token Details and wait for supply to load | ||||
| // The supply is correctly rendered | await userEvent.click( | ||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| expect( | expect( | ||||
| await screen.findByText('111,367.0000 (var.)'), | await screen.findByText(/111,367\.\d+ \(var\.\)/), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // Click Send | // Click Send - open dropdown and click Send | ||||
| await userEvent.click(screen.getByTitle('Toggle Send')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(screen.getByRole('button', { name: 'Send' })); | |||||
| // Wait for address input to render | // Wait for address input to render (send form) | ||||
| expect( | expect( | ||||
| await screen.findByPlaceholderText('Address'), | await screen.findByPlaceholderText('Address'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // On load, default action for ALP is to send it | |||||
| const sendActionSwitch = screen.getByTitle('Toggle Send'); | |||||
| await waitFor(() => expect(sendActionSwitch).toBeChecked()); | |||||
| // We see an Address input | // We see an Address input | ||||
| const addrInput = screen.getByPlaceholderText('Address'); | const addrInput = screen.getByPlaceholderText('Address'); | ||||
| expect(addrInput).toBeInTheDocument(); | expect(addrInput).toBeInTheDocument(); | ||||
| // Send button is disabled before address and amount entry | // Send button is disabled before address and amount entry | ||||
| const sendButton = screen.getByRole('button', { | const sendButton = screen.getByRole('button', { | ||||
| name: /Send tCRD/, | name: /Send tCRD/, | ||||
| }); | }); | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | it('We can burn an ALP token with change', async () => { | ||||
| const { tokenName } = alpMocks.token.genesisInfo; | const { tokenName } = alpMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Wait for supply and actions to load | // Expand Token Details and wait for supply to load | ||||
| // The supply is correctly rendered | await userEvent.click( | ||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| expect( | expect( | ||||
| await screen.findByText('111,367.0000 (var.)'), | await screen.findByText(/111,367\.\d+ \(var\.\)/), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for ALP is to list | // On load, default action for ALP is to list | ||||
| // Select burn | // Select burn | ||||
| await userEvent.click(screen.getByTitle('Toggle Burn')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(screen.getByRole('button', { name: 'Burn' })); | |||||
| await userEvent.type(screen.getByPlaceholderText('Burn Amount'), '1'); | await userEvent.type(screen.getByPlaceholderText('Burn Amount'), '1'); | ||||
| // Click the Burn button | // Click the Burn button | ||||
| // Note we button title is the token ticker | // Note we button title is the token ticker | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { name: /Burn tCRD/ }), | await screen.findByRole('button', { name: /Burn tCRD/ }), | ||||
| ); | ); | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | it('We can burn an ALP token without change', async () => { | ||||
| const { tokenName } = alpMocks.token.genesisInfo; | const { tokenName } = alpMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Wait for supply and actions to load | // Expand Token Details and wait for supply to load | ||||
| // The supply is correctly rendered | await userEvent.click( | ||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| expect( | expect( | ||||
| await screen.findByText('111,367.0000 (var.)'), | await screen.findByText(/111,367\.\d+ \(var\.\)/), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for ALP is to list | // On load, default action for ALP is to list | ||||
| // Select burn | // Select burn | ||||
| await userEvent.click(screen.getByTitle('Toggle Burn')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(screen.getByRole('button', { name: 'Burn' })); | |||||
| // Hit max for max burn | // Hit max for max burn | ||||
| await userEvent.click(screen.getByRole('button', { name: /max/ })); | await userEvent.click(screen.getByRole('button', { name: /max/ })); | ||||
| // Max is input | // Max is input | ||||
| const thisWalletAlpBalance = '100.0000'; | const thisWalletAlpBalance = '100.0000'; | ||||
| expect(screen.getByPlaceholderText('Burn Amount')).toHaveValue( | expect(screen.getByPlaceholderText('Burn Amount')).toHaveValue( | ||||
| thisWalletAlpBalance, | thisWalletAlpBalance, | ||||
| ▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | it('We can mint max one-output ALP token qty', async () => { | ||||
| const { tokenName } = alpMocks.token.genesisInfo; | const { tokenName } = alpMocks.token.genesisInfo; | ||||
| // 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(); | ||||
| // Wait for supply and actions to load | // Expand Token Details and wait for supply to load | ||||
| // The supply is correctly rendered | await userEvent.click( | ||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| expect( | expect( | ||||
| await screen.findByText('111,367.0000 (var.)'), | await screen.findByText(/111,367\.\d+ \(var\.\)/), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // Select mint | // Select mint | ||||
| await userEvent.click(screen.getByTitle('Toggle Mint')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(screen.getByRole('button', { name: 'Mint' })); | |||||
| // Max qty | // Max qty | ||||
| await userEvent.click(screen.getByRole('button', { name: /max/ })); | await userEvent.click(screen.getByRole('button', { name: /max/ })); | ||||
| // Max is input | // Max is input | ||||
| const maxMintQty = '28147497671.0655'; | const maxMintQty = '28147497671.0655'; | ||||
| expect(screen.getByPlaceholderText('Mint Amount')).toHaveValue( | expect(screen.getByPlaceholderText('Mint Amount')).toHaveValue( | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | it('We can list an ALP fungible token', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token image is rendered | // Token image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${alpMocks.tokenId}`), | screen.getByAltText(`icon for ${alpMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for ALP is to list it | // Click Sell to show the list form | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toBeEnabled(); | await userEvent.click( | ||||
| await screen.findByRole('button', { name: '− Sell' }), | |||||
| ); | |||||
| // The list button is disabled on load | // The list button is disabled on load | ||||
| const listButton = await screen.findByRole('button', { | const listButton = await screen.findByRole('button', { | ||||
| name: /List Test CRD/, | name: /List Test CRD/, | ||||
| }); | }); | ||||
| expect(listButton).toBeDisabled(); | expect(listButton).toBeDisabled(); | ||||
| // The price input is disabled until qty values are entered | // The price input is disabled until qty values are entered | ||||
| const priceInput = screen.getByPlaceholderText( | const priceInput = screen.getByPlaceholderText( | ||||
| 'Enter list price (per token)', | 'Enter list price (per token)', | ||||
| ); | ); | ||||
| expect(priceInput).toBeDisabled(); | expect(priceInput).toBeDisabled(); | ||||
| // Enter token balance as offered qty | // Enter token balance as offered qty | ||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '100'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '100', | |||||
| ); | |||||
| // The price input is no longer disabled | // The price input is no longer disabled | ||||
| expect(priceInput).toBeEnabled(); | expect(priceInput).toBeEnabled(); | ||||
| // Enter a price | // Enter a price | ||||
| await userEvent.type(priceInput, '0.001'); | await userEvent.type(priceInput, '0.001'); | ||||
| const minQtyInput = screen.getByPlaceholderText('Min qty'); | const minQtyInput = screen.getByPlaceholderText('Min qty'); | ||||
| ▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | it('We can redeem XECX for XEC 1:1 using a workflow unique to XECX', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for XECX is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(await screen.findByTitle('Toggle Redeem XECX')).toBeEnabled(); | await userEvent.click( | ||||
| 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 XECX for XEC/, | name: /Redeem XECX 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( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '5.45', | '5.45', | ||||
| ); | ); | ||||
| // This is below dust so we get an error | // This is below dust so we get an error | ||||
| expect( | expect( | ||||
| screen.getByText('Cannot redeem less than 5.46 XECX'), | screen.getByText('Cannot redeem less than 5.46 XECX'), | ||||
| ).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('Offered qty')); | await userEvent.clear( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| ); | |||||
| await userEvent.type( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '10000', | '10000', | ||||
| ); | ); | ||||
| expect(screen.getByPlaceholderText('Offered qty')).toHaveValue(10000); | expect(screen.getByPlaceholderText('agoraPartialTokenQty')).toHaveValue( | ||||
| 10000, | |||||
| ); | |||||
| // The redeem button is now enabled | // The redeem button is now enabled | ||||
| expect(redeemButton).toBeEnabled(); | expect(redeemButton).toBeEnabled(); | ||||
| // The fiat price is previewed correctly | // The fiat price is previewed correctly | ||||
| expect( | expect( | ||||
| screen.getByText('1 XEC ($0.00003000 USD) per token'), | screen.getByText('1 XEC ($0.00003000 USD) per token'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | it('We see expected alert in XECX redemption workflow for hot wallet balance', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for XECX is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(screen.getByTitle('Toggle Redeem XECX')).toBeEnabled(); | await userEvent.click( | ||||
| 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 XECX for XEC/, | name: /Redeem XECX for XEC/, | ||||
| }); | }); | ||||
| await waitFor(() => expect(redeemButton).toBeDisabled()); | await waitFor(() => expect(redeemButton).toBeDisabled()); | ||||
| // We redeem 10k XECX | // We redeem 10k XECX | ||||
| await userEvent.type( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '10000', | '10000', | ||||
| ); | ); | ||||
| expect(screen.getByPlaceholderText('Offered qty')).toHaveValue(10000); | expect(screen.getByPlaceholderText('agoraPartialTokenQty')).toHaveValue( | ||||
| 10000, | |||||
| ); | |||||
| // The redeem button is now enabled | // The redeem button is now enabled | ||||
| expect(redeemButton).toBeEnabled(); | expect(redeemButton).toBeEnabled(); | ||||
| // The fiat price is previewed correctly | // The fiat price is previewed correctly | ||||
| expect( | expect( | ||||
| screen.getByText('1 XEC ($0.00003000 USD) per token'), | screen.getByText('1 XEC ($0.00003000 USD) per token'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | it('We DO NOT see expected alert in XECX redemption workflow for hot wallet balance if there is some error determining the hot wallet balance', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // XECX token icon is rendered | // XECX token icon is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | screen.getByAltText(`icon for ${tokenMockXecx.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for XECX is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(screen.getByTitle('Toggle Redeem XECX')).toBeEnabled(); | await userEvent.click( | ||||
| 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 XECX for XEC/, | name: /Redeem XECX for XEC/, | ||||
| }); | }); | ||||
| await waitFor(() => expect(redeemButton).toBeDisabled()); | await waitFor(() => expect(redeemButton).toBeDisabled()); | ||||
| // We redeem 10k XECX | // We redeem 10k XECX | ||||
| await userEvent.type( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '10000', | '10000', | ||||
| ); | ); | ||||
| expect(screen.getByPlaceholderText('Offered qty')).toHaveValue(10000); | expect(screen.getByPlaceholderText('agoraPartialTokenQty')).toHaveValue( | ||||
| 10000, | |||||
| ); | |||||
| // The redeem button is now enabled | // The redeem button is now enabled | ||||
| expect(redeemButton).toBeEnabled(); | expect(redeemButton).toBeEnabled(); | ||||
| // The fiat price is previewed correctly | // The fiat price is previewed correctly | ||||
| expect( | expect( | ||||
| screen.getByText('1 XEC ($0.00003000 USD) per token'), | screen.getByText('1 XEC ($0.00003000 USD) per token'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| ▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | it('We can redeem 1 Firma for $1 of XEC using a workflow unique to Firma', async () => { | ||||
| ).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(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for FIRMA is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(screen.getByTitle('Toggle Redeem FIRMA')).toBeEnabled(); | await userEvent.click( | ||||
| 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 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( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '0.009', | '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'), | ||||
| ).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('Offered qty')); | await userEvent.clear( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| ); | |||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '10'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '10', | |||||
| ); | |||||
| expect(screen.getByPlaceholderText('Offered qty')).toHaveValue(10); | expect(screen.getByPlaceholderText('agoraPartialTokenQty')).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 | ||||
| ▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | it('FIRMA redeem is disabled if the hot wallet cannot cover redeem amount', async () => { | ||||
| ).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(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for FIRMA is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(screen.getByTitle('Toggle Redeem FIRMA')).toBeEnabled(); | await userEvent.click( | ||||
| 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 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('Offered qty'), '10'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '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 | ||||
| ▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | it('We show expected error if we are unable to get FIRMA bid price from API', async () => { | ||||
| ).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(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for FIRMA is to redeem it | // Click Redeem to show the redeem form | ||||
| expect(screen.getByTitle('Toggle Redeem FIRMA')).toBeEnabled(); | await userEvent.click( | ||||
| 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 for XEC/, | ||||
| }); | }); | ||||
| 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( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Offered qty'), | screen.getByPlaceholderText('agoraPartialTokenQty'), | ||||
| '0.009', | '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'), | ||||
| ).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('Offered qty')); | await userEvent.clear( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| ); | |||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '10'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '10', | |||||
| ); | |||||
| expect(screen.getByPlaceholderText('Offered qty')).toHaveValue(10); | expect(screen.getByPlaceholderText('agoraPartialTokenQty')).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); | ||||
| // Price error | // Price error | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | it('We can SEND or BURN an SLP MINT VAULT token', async () => { | ||||
| // 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(); | ||||
| // Wait for supply and actions to load | // Wait for supply and actions to load | ||||
| // The supply is correctly rendered and is variable for a MINT VAULT token even though | // The supply is correctly rendered and is variable for a MINT VAULT token even though | ||||
| // we have no mint batons | // we have no mint batons - expand Token Details to see supply | ||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: /Token Details/i }), | |||||
| ); | |||||
| expect( | expect( | ||||
| await screen.findByText('10,000,000 (var.)'), | await screen.findByText(/10,000,000 \(var\.\)/), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for SLP MINT is to list it | // On load, default action for SLP MINT is to list it | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toBeChecked(); | expect( | ||||
| screen.getByRole('button', { name: '− Sell' }), | |||||
| ).toBeInTheDocument(); | |||||
| // Click Send | // Click Send - open dropdown and click Send | ||||
| const sendActionSwitch = screen.getByTitle('Toggle Send'); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(sendActionSwitch); | await userEvent.click(screen.getByRole('button', { name: 'Send' })); | ||||
| await waitFor(() => expect(sendActionSwitch).toBeChecked()); | |||||
| // Wait for address input to render | // Wait for address input to render | ||||
| expect( | expect( | ||||
| await screen.findByPlaceholderText('Address'), | await screen.findByPlaceholderText('Address'), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // We see an Address input | // We see an Address input | ||||
| const addrInput = screen.getByPlaceholderText('Address'); | const addrInput = screen.getByPlaceholderText('Address'); | ||||
| Show All 25 Lines | it('We can SEND or BURN an SLP MINT VAULT token', async () => { | ||||
| expect(sendTokenSuccessNotification).toHaveAttribute( | expect(sendTokenSuccessNotification).toHaveAttribute( | ||||
| 'href', | 'href', | ||||
| `${explorer.blockExplorerUrl}/tx/${txid}`, | `${explorer.blockExplorerUrl}/tx/${txid}`, | ||||
| ); | ); | ||||
| // We can also burn an SLP MINT VAULT token | // We can also burn an SLP MINT VAULT token | ||||
| // Select burn | // Select burn | ||||
| await userEvent.click(screen.getByTitle('Toggle Burn')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click(screen.getByRole('button', { name: 'Burn' })); | |||||
| await userEvent.type(screen.getByPlaceholderText('Burn Amount'), '1'); | await userEvent.type(screen.getByPlaceholderText('Burn Amount'), '1'); | ||||
| // Click the Burn button | // Click the Burn button | ||||
| // Note we button title is the token ticker | // Note we button title is the token ticker | ||||
| await userEvent.click( | await userEvent.click( | ||||
| await screen.findByRole('button', { name: /Burn MVTT β/ }), | await screen.findByRole('button', { name: /Burn MVTT β/ }), | ||||
| ); | ); | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | it('We can list a MINT VAULT fungible token', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token image is rendered | // Token image is rendered | ||||
| expect( | expect( | ||||
| screen.getByAltText(`icon for ${slpMintVaultMocks.tokenId}`), | screen.getByAltText(`icon for ${slpMintVaultMocks.tokenId}`), | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Token actions are available | // Token actions are available | ||||
| expect(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for MINT vault is to list it | // Click Sell to show the list form | ||||
| expect(screen.getByTitle('Toggle Sell Token')).toBeEnabled(); | await userEvent.click( | ||||
| await screen.findByRole('button', { name: '− Sell' }), | |||||
| ); | |||||
| // The list button is disabled on load | // The list button is disabled on load | ||||
| const listButton = await screen.findByRole('button', { | const listButton = await screen.findByRole('button', { | ||||
| name: /List Mint Vault Test Token Beta/, | name: /List Mint Vault Test Token Beta/, | ||||
| }); | }); | ||||
| expect(listButton).toBeDisabled(); | expect(listButton).toBeDisabled(); | ||||
| // The price input is disabled until qty values are entered | // The price input is disabled until qty values are entered | ||||
| const priceInput = screen.getByPlaceholderText( | const priceInput = screen.getByPlaceholderText( | ||||
| 'Enter list price (per token)', | 'Enter list price (per token)', | ||||
| ); | ); | ||||
| expect(priceInput).toBeDisabled(); | expect(priceInput).toBeDisabled(); | ||||
| // Enter token balance as offered qty | // Enter token balance as offered qty | ||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '100'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '100', | |||||
| ); | |||||
| // The price input is no longer disabled | // The price input is no longer disabled | ||||
| expect(priceInput).toBeEnabled(); | expect(priceInput).toBeEnabled(); | ||||
| // Enter a price | // Enter a price | ||||
| await userEvent.type(priceInput, '1'); | await userEvent.type(priceInput, '1'); | ||||
| const minQtyInput = screen.getByPlaceholderText('Min qty'); | const minQtyInput = screen.getByPlaceholderText('Min qty'); | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | it('We do not allow users to list FIRMA below the bid price', async () => { | ||||
| ).toBeInTheDocument(); | ).toBeInTheDocument(); | ||||
| // Firma token icon is rendered | // Firma 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(screen.getByTitle('Token Actions')).toBeInTheDocument(); | expect( | ||||
| await screen.findByRole('button', { name: '+ Buy' }), | |||||
| ).toBeInTheDocument(); | |||||
| // On load, default action for FIRMA is to redeem it | // On load, default action for FIRMA is to redeem it | ||||
| expect(screen.getByTitle('Toggle Redeem FIRMA')).toBeEnabled(); | expect(screen.getByRole('button', { name: '− Redeem' })).toBeEnabled(); | ||||
| // We can though manually click to list it | // We can though manually click to list it - use dropdown "List token" | ||||
| await userEvent.click(screen.getByTitle('Toggle Sell Token')); | await userEvent.click(screen.getByRole('button', { name: '⋯' })); | ||||
| await userEvent.click( | |||||
| screen.getByRole('button', { name: 'List token' }), | |||||
| ); | |||||
| // We can try to list for less than $1 | // We can try to list for less than $1 | ||||
| await userEvent.type(screen.getByPlaceholderText('Offered qty'), '1'); | await userEvent.type( | ||||
| screen.getByPlaceholderText('agoraPartialTokenQty'), | |||||
| '1', | |||||
| ); | |||||
| // List for 1,000 XEC | // List for 1,000 XEC | ||||
| await userEvent.type( | await userEvent.type( | ||||
| screen.getByPlaceholderText('Enter list price (per token)'), | screen.getByPlaceholderText('Enter list price (per token)'), | ||||
| '1000', | '1000', | ||||
| ); | ); | ||||
| // Make sure the min buy is correct | // Make sure the min buy is correct | ||||
| await userEvent.clear(screen.getByPlaceholderText('Min qty')); | const minQtyInput = screen.getByPlaceholderText('Min qty'); | ||||
| await userEvent.type(screen.getByPlaceholderText('Min qty'), '1'); | await userEvent.clear(minQtyInput); | ||||
| 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/, | ||||
| }); | }); | ||||
| // try to list | // try to list | ||||
| await userEvent.click(listButton); | await userEvent.click(listButton); | ||||
| Show All 15 Lines | |||||