import QtQuick 2.15 import QtTest 1.15 import StatusQ 0.1 // See #10218 import StatusQ.Core 0.1 import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 import QtQuick.Controls 2.15 import Models 1.0 import Storybook 1.0 import utils 1.0 import shared.stores 1.0 import AppLayouts.Wallet.popups.swap 1.0 import AppLayouts.Wallet.stores 1.0 import AppLayouts.Wallet 1.0 import AppLayouts.Wallet.adaptors 1.0 Item { id: root width: 800 height: 600 readonly property var dummySwapTransactionRoutes: SwapTransactionRoutes {} readonly property var swapStore: SwapStore { signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription) signal transactionSent(var chainId,var txHash, var uuid, var error) signal transactionSendingComplete(var txHash, var status) readonly property var accounts: WalletAccountsModel {} readonly property var flatNetworks: NetworksModel.flatNetworks readonly property bool areTestNetworksEnabled: true function getWei2Eth(wei, decimals) { return wei/(10**decimals) } function fetchSuggestedRoutes(uuid, accountFrom, accountTo, amount, tokenFrom, tokenTo, disabledFromChainIDs, disabledToChainIDs, preferredChainIDs, sendType, lockedInAmounts) { swapStore.fetchSuggestedRoutesCalled() } function authenticateAndTransfer(uuid, accountFrom, accountTo, tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths) {} // local signals for testing function calls signal fetchSuggestedRoutesCalled() } readonly property SwapModalAdaptor swapAdaptor: SwapModalAdaptor { currencyStore: CurrenciesStore {} walletAssetsStore: WalletAssetsStore { id: thisWalletAssetStore walletTokensStore: TokensStore { plainTokensBySymbolModel: TokensBySymbolModel {} getDisplayAssetsBelowBalanceThresholdDisplayAmount: () => 0 } readonly property var baseGroupedAccountAssetModel: GroupedAccountsAssetsModel {} assetsWithFilteredBalances: thisWalletAssetStore.groupedAccountsAssetsModel } swapStore: root.swapStore swapFormData: root.swapFormData swapOutputData: SwapOutputData{} } readonly property var tokenSelectorAdaptor: TokenSelectorViewAdaptor { assetsModel: swapAdaptor.walletAssetsStore.groupedAccountAssetsModel flatNetworksModel: swapStore.flatNetworks currentCurrency: swapAdaptor.currencyStore.currentCurrency plainTokensBySymbolModel: root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel enabledChainIds: !!root.swapFormData && root.swapFormData.selectedNetworkChainId !== - 1 ? [root.swapFormData.selectedNetworkChainId] : [] accountAddress: !!root.swapFormData && root.swapFormData.selectedAccountAddress } property SwapInputParamsForm swapFormData: SwapInputParamsForm { defaultToTokenKey: Constants.swap.testStatusTokenKey } Component { id: componentUnderTest SwapModal { swapInputParamsForm: root.swapFormData swapAdaptor: root.swapAdaptor loginType: Constants.LoginType.Password } } SignalSpy { id: formValuesChanged target: swapFormData signalName: "formValuesChanged" } SignalSpy { id: fetchSuggestedRoutesCalled target: swapStore signalName: "fetchSuggestedRoutesCalled" } TestCase { name: "SwapModal" when: windowShown property SwapModal controlUnderTest: null // helper functions ------------------------------------------------------------- function init() { swapAdaptor.swapFormData = root.swapFormData controlUnderTest = createTemporaryObject(componentUnderTest, root, { swapInputParamsForm: root.swapFormData}) } function cleanup() { root.swapFormData.resetFormData() formValuesChanged.clear() } function launchAndVerfyModal() { formValuesChanged.clear() verify(!!controlUnderTest) controlUnderTest.open() verify(!!controlUnderTest.opened) } function closeAndVerfyModal() { verify(!!controlUnderTest) controlUnderTest.close() verify(!controlUnderTest.opened) formValuesChanged.clear() root.swapFormData.resetFormData() } function getAndVerifyAccountsModalHeader() { const accountsModalHeader = findChild(controlUnderTest, "accountSelector") verify(!!accountsModalHeader) return accountsModalHeader } function launchAccountSelectionPopup(accountsModalHeader) { // Launch account selection popup verify(!accountsModalHeader.control.popup.opened) mouseClick(accountsModalHeader) waitForRendering(accountsModalHeader) verify(!!accountsModalHeader.control.popup.opened) mouseMove(accountsModalHeader) return accountsModalHeader } function verifyLoadingAndNoErrorsState(payPanel, receivePanel) { // verify loading state was set and no errors currently verify(!root.swapAdaptor.validSwapProposalReceived) verify(root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.rawPaths, []) compare(root.swapAdaptor.swapOutputData.hasError, false) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(payPanel.bottomTextLoading) compare(payPanel.selectedHoldingId, root.swapFormData.fromTokensKey) compare(payPanel.value, Number(root.swapFormData.fromTokenAmount)) compare(payPanel.rawValue, SQUtils.AmountsArithmetic.fromNumber(root.swapFormData.fromTokenAmount, root.swapAdaptor.fromToken.decimals).toString()) verify(payPanel.valueValid) verify(receivePanel.mainInputLoading) verify(receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") } // end helper functions ------------------------------------------------------------- function test_floating_header_default_account() { verify(!!controlUnderTest) /* using a for loop set different accounts as default index and check if the correct values are displayed in the floating header*/ for (let i = 0; i< swapAdaptor.nonWatchAccounts.count; i++) { const nonWatchAccount = swapAdaptor.nonWatchAccounts.get(i) root.swapFormData.selectedAccountAddress = nonWatchAccount.address // Launch popup launchAndVerfyModal() const floatingHeaderBackground = findChild(controlUnderTest, "headerBackground") verify(!!floatingHeaderBackground) compare(floatingHeaderBackground.color.toString().toUpperCase(), Utils.getColorForId(nonWatchAccount.colorId).toString().toUpperCase()) const headerContentItemText = findChild(controlUnderTest, "textContent") verify(!!headerContentItemText) compare(headerContentItemText.text, nonWatchAccount.name) const headerContentItemEmoji = findChild(controlUnderTest, "assetContent") verify(!!headerContentItemEmoji) compare(headerContentItemEmoji.asset.emoji, nonWatchAccount.emoji) } closeAndVerfyModal() } function test_floating_header_doesnt_contain_watch_accounts() { // main input list from store should contian watch accounts let hasWatchAccount = false for(let i =0; i< swapStore.accounts.count; i++) { if(swapStore.accounts.get(i).walletType === Constants.watchWalletType) { hasWatchAccount = true break } } verify(!!hasWatchAccount) // launch modal and get the account selection header launchAndVerfyModal() const accountsModalHeader = getAndVerifyAccountsModalHeader() // header model should not contain watch accounts let floatingHeaderHasWatchAccount = false for(let i =0; i< accountsModalHeader.model.count; i++) { if(accountsModalHeader.model.get(i).walletType === Constants.watchWalletType) { floatingHeaderHasWatchAccount = true break } } verify(!floatingHeaderHasWatchAccount) closeAndVerfyModal() } function test_floating_header_list_items() { // Launch popup and account selection modal launchAndVerfyModal() const accountsModalHeader = getAndVerifyAccountsModalHeader() launchAccountSelectionPopup(accountsModalHeader) const comboBoxList = findChild(controlUnderTest, "accountSelectorList") verify(!!comboBoxList) waitForRendering(comboBoxList) for(let i =0; i< comboBoxList.model.count; i++) { let delegateUnderTest = comboBoxList.itemAtIndex(i) compare(delegateUnderTest.title, swapAdaptor.nonWatchAccounts.get(i).name) compare(delegateUnderTest.subTitle, SQUtils.Utils.elideAndFormatWalletAddress(swapAdaptor.nonWatchAccounts.get(i).address)) compare(delegateUnderTest.asset.color.toString().toUpperCase(), swapAdaptor.nonWatchAccounts.get(i).color.toString().toUpperCase()) compare(delegateUnderTest.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji) const walletAccountCurrencyBalance = findChild(delegateUnderTest, "walletAccountCurrencyBalance") verify(!!walletAccountCurrencyBalance) verify(walletAccountCurrencyBalance.text, LocaleUtils.currencyAmountToLocaleString(swapAdaptor.nonWatchAccounts.get(i).currencyBalance)) // check if selected item in combo box is highlighted with the right color if(comboBoxList.currentIndex === i) { verify(delegateUnderTest.color, Theme.palette.statusListItem.highlightColor) } else { verify(delegateUnderTest.color, Theme.palette.transparent) } // TODO: always null not sure why // const walletAccountTypeIcon = findChild(delegateUnderTest, "walletAccountTypeIcon") // verify(!!walletAccountTypeIcon) // compare(walletAccountTypeIcon.icon, swapAdaptor.nonWatchAccounts.get(i).walletType === Constants.watchWalletType ? "show" : delegateUnderTest.model.migratedToKeycard ? "keycard": "") // Hover over the item and check hovered state mouseMove(delegateUnderTest, delegateUnderTest.width/2, delegateUnderTest.height/2) verify(delegateUnderTest.sensor.containsMouse) compare(delegateUnderTest.title, swapAdaptor.nonWatchAccounts.get(i).name) compare(delegateUnderTest.subTitle, WalletUtils.colorizedChainPrefix(WalletUtils.getNetworkShortNames(swapAdaptor.nonWatchAccounts.get(i).preferredSharingChainIds, root.swapStore.flatNetworks)), "Randomly failing locally. Add a bug if you see this failing in CI") verify(delegateUnderTest.color, Theme.palette.baseColor2) } controlUnderTest.close() } function test_floating_header_after_setting_fromAsset() { // Launch popup launchAndVerfyModal() // launch account selection dropdown const accountsModalHeader = getAndVerifyAccountsModalHeader() launchAccountSelectionPopup(accountsModalHeader) const comboBoxList = findChild(accountsModalHeader, "accountSelectorList") verify(!!comboBoxList) // before setting network chainId and fromTokensKey the header should not have balances for(let i =0; i< comboBoxList.model.count; i++) { let delegateUnderTest = comboBoxList.itemAtIndex(i) verify(!delegateUnderTest.model.accountBalance) } // close account selection dropdown accountsModalHeader.control.popup.close() // set network chainId and fromTokensKey and verify balances in account selection dropdown root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId root.swapFormData.fromTokensKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(0).key compare(controlUnderTest.swapInputParamsForm.selectedNetworkChainId, root.swapFormData.selectedNetworkChainId) compare(controlUnderTest.swapInputParamsForm.fromTokensKey, root.swapFormData.fromTokensKey) // launch account selection dropdown launchAccountSelectionPopup(accountsModalHeader) verify(!!comboBoxList) for(let i =0; i< comboBoxList.model.count; i++) { let delegateUnderTest = comboBoxList.itemAtIndex(i) verify(!!delegateUnderTest.model.fromToken) verify(!!delegateUnderTest.model.accountBalance) compare(delegateUnderTest.inlineTagModel, 1) const inlineTagDelegate_0 = findChild(delegateUnderTest, "inlineTagDelegate_0") verify(!!inlineTagDelegate_0) const balance = delegateUnderTest.model.accountBalance.balance compare(inlineTagDelegate_0.asset.name, Style.svg("tiny/%1".arg(delegateUnderTest.model.accountBalance.iconUrl))) compare(inlineTagDelegate_0.asset.color.toString().toUpperCase(), delegateUnderTest.model.accountBalance.chainColor.toString().toUpperCase()) compare(inlineTagDelegate_0.titleText.color, balance === "0" ? Theme.palette.baseColor1 : Theme.palette.directColor1) let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(balance, delegateUnderTest.model.fromToken.decimals) compare(inlineTagDelegate_0.title, balance === "0" ? "0 %1".arg(delegateUnderTest.model.fromToken.symbol) : root.swapAdaptor.formatCurrencyAmount(bigIntBalance, delegateUnderTest.model.fromToken.symbol)) } closeAndVerfyModal() } function test_floating_header_selection() { // Launch popup launchAndVerfyModal() const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const amountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!amountToSendInput) verify(amountToSendInput.cursorVisible) for(let i =0; i< swapAdaptor.nonWatchAccounts.count; i++) { // launch account selection dropdown const accountsModalHeader = getAndVerifyAccountsModalHeader() launchAccountSelectionPopup(accountsModalHeader) const comboBoxList = findChild(accountsModalHeader, "accountSelectorList") verify(!!comboBoxList) let delegateUnderTest = comboBoxList.itemAtIndex(i) mouseClick(delegateUnderTest) waitForRendering(delegateUnderTest) verify(accountsModalHeader.control.popup.closed) // The input params form's slected Index should be updated as per this selection compare(root.swapFormData.selectedAccountAddress, swapAdaptor.nonWatchAccounts.get(i).address) // The comboBox item should reflect chosen account const floatingHeaderBackground = findChild(accountsModalHeader, "headerBackground") verify(!!floatingHeaderBackground) compare(floatingHeaderBackground.color.toString().toUpperCase(), swapAdaptor.nonWatchAccounts.get(i).color.toString().toUpperCase()) const headerContentItemText = findChild(accountsModalHeader, "textContent") verify(!!headerContentItemText) compare(headerContentItemText.text, swapAdaptor.nonWatchAccounts.get(i).name) const headerContentItemEmoji = findChild(accountsModalHeader, "assetContent") verify(!!headerContentItemEmoji) compare(headerContentItemEmoji.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji) verify(amountToSendInput.cursorVisible) } closeAndVerfyModal() } function test_network_default_and_selection() { // Launch popup launchAndVerfyModal() const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const amountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!amountToSendInput) verify(amountToSendInput.cursorVisible) // get network comboBox const networkComboBox = findChild(controlUnderTest, "networkFilter") verify(!!networkComboBox) // check default value of network comboBox, should be mainnet compare(root.swapFormData.selectedNetworkChainId, -1) compare(root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId, 11155111 /*Sepolia Mainnet*/) // lets ensure that the selected one is correctly set for (let i=0; i balances.chainId === root.swapFormData.selectedNetworkChainId).filter(balances => balances.account === accountDelegateUnderTest.model.address) verify(!!filteredBalances) let accountBalance = filteredBalances.length > 0 ? filteredBalances[0]: { balance: "0", iconUrl: networkModelItem.iconUrl, chainColor: networkModelItem.chainColor} verify(!!accountBalance) let fromToken = SQUtils.ModelUtils.getByKey(root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel, "key", root.swapFormData.fromTokensKey) verify(!!fromToken) let bigIntBalance = SQUtils.AmountsArithmetic.toNumber(accountBalance.balance, fromToken.decimals) compare(inlineTagDelegate_0.title, bigIntBalance === 0 ? "0 %1".arg(fromToken.symbol) : root.swapAdaptor.formatCurrencyAmount(bigIntBalance, fromToken.symbol)) } // close account selection dropdown accountsModalHeader.control.popup.close() } root.swapFormData.selectedNetworkChainId = -1 networkComboBox.control.popup.close() closeAndVerfyModal() } function test_edit_slippage() { // Launch popup launchAndVerfyModal() // test default values for the various footer items for slippage const maxSlippageText = findChild(controlUnderTest, "maxSlippageText") verify(!!maxSlippageText) compare(maxSlippageText.text, qsTr("Max slippage:")) const maxSlippageValue = findChild(controlUnderTest, "maxSlippageValue") verify(!!maxSlippageValue) const editSlippageButton = findChild(controlUnderTest, "editSlippageButton") verify(!!editSlippageButton) const editSlippagePanel = findChild(controlUnderTest, "editSlippagePanel") verify(!!editSlippagePanel) verify(!editSlippagePanel.visible) // set swap proposal to ready and check state of the edit slippage buttons and max slippage values root.swapAdaptor.validSwapProposalReceived = true compare(maxSlippageValue.text, "%1%".arg(0.5)) verify(editSlippageButton.visible) // clicking on editSlippageButton should show the edit slippage panel mouseClick(editSlippageButton) verify(!editSlippageButton.visible) verify(editSlippagePanel.visible) const slippageSelector = findChild(editSlippagePanel, "slippageSelector") verify(!!slippageSelector) verify(slippageSelector.valid) compare(slippageSelector.value, 0.5) const buttonsRepeater = findChild(slippageSelector, "buttonsRepeater") verify(!!buttonsRepeater) waitForRendering(buttonsRepeater) for(let i =0; i< buttonsRepeater.count; i++) { let buttonUnderTest = buttonsRepeater.itemAt(i) verify(!!buttonUnderTest) // the mouseClick(buttonUnderTest) doesnt seem to work buttonUnderTest.clicked() verify(slippageSelector.valid) compare(slippageSelector.value, buttonUnderTest.value) compare(maxSlippageValue.text, "%1%".arg(buttonUnderTest.value)) } const signButton = findChild(controlUnderTest, "signButton") verify(!!signButton) verify(signButton.enabled) } function test_modal_swap_proposal_setup() { root.swapAdaptor.reset() // Launch popup launchAndVerfyModal() waitForItemPolished(controlUnderTest.contentItem) const maxFeesText = findChild(controlUnderTest, "maxFeesText") verify(!!maxFeesText) const maxFeesValue = findChild(controlUnderTest, "maxFeesValue") verify(!!maxFeesValue) const signButton = findChild(controlUnderTest, "signButton") verify(!!signButton) const errorTag = findChild(controlUnderTest, "errorTag") verify(!!errorTag) const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const receivePanel = findChild(controlUnderTest, "receivePanel") verify(!!receivePanel) // Check max fees values and sign button state when nothing is set compare(maxFeesText.text, qsTr("Max fees:")) compare(maxFeesValue.text, "--") verify(!signButton.interactive) verify(!errorTag.visible) // set input values in the form correctly root.swapFormData.fromTokensKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(0).key formValuesChanged.wait() root.swapFormData.toTokenKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(1).key root.swapFormData.fromTokenAmount = "0.001" waitForRendering(receivePanel) formValuesChanged.wait() root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId formValuesChanged.wait() root.swapFormData.selectedAccountAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event that no routes were found with unknown error const txRoutes = root.dummySwapTransactionRoutes.txNoRoutes txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, "NO_ROUTES", "No routes found") // verify loading state was removed and that error was displayed verify(!root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, "") compare(root.swapAdaptor.swapOutputData.totalFees, 0) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, true) verify(errorTag.visible) verify(errorTag.text, qsTr("An error has occured, please try again")) verify(!signButton.interactive) compare(signButton.text, qsTr("Swap")) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.00011" waitForRendering(receivePanel) formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event that no routes were found due to not enough token balance txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, Constants.routerErrorCodes.router.errNotEnoughTokenBalance, "errNotEnoughTokenBalance") // verify loading state was removed and that error was displayed verify(!root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, "") compare(root.swapAdaptor.swapOutputData.totalFees, 0) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, true) verify(errorTag.visible) verify(errorTag.text, qsTr("Insufficient funds for swap")) verify(!signButton.interactive) compare(signButton.text, qsTr("Swap")) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.00012" waitForRendering(receivePanel) formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event that no routes were found due to not enough eth balance txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, Constants.routerErrorCodes.router.errNotEnoughNativeBalance, "errNotEnoughNativeBalance") // verify loading state was removed and that error was displayed verify(!root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, "") compare(root.swapAdaptor.swapOutputData.totalFees, 0) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, true) verify(errorTag.visible) verify(errorTag.text, qsTr("Insufficient funds to pay gas fees")) verify(!signButton.interactive) compare(signButton.text, qsTr("Swap")) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.00013" waitForRendering(receivePanel) formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event that no routes were found due to price timeout txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, Constants.routerErrorCodes.processor.errPriceTimeout, "errPriceTimeout") // verify loading state was removed and that error was displayed verify(!root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, "") compare(root.swapAdaptor.swapOutputData.totalFees, 0) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, true) verify(errorTag.visible) verify(errorTag.text, qsTr("Fetching the price took longer than expected. Please, try again later.")) verify(!signButton.interactive) compare(signButton.text, qsTr("Swap")) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.00014" waitForRendering(receivePanel) formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event that no routes were found due to not enough liquidity txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, Constants.routerErrorCodes.processor.errNotEnoughLiquidity, "errNotEnoughLiquidity") // verify loading state was removed and that error was displayed verify(!root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, "") compare(root.swapAdaptor.swapOutputData.totalFees, 0) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, true) verify(errorTag.visible) verify(errorTag.text, qsTr("Not enough liquidity. Lower token amount or try again later.")) verify(!signButton.interactive) compare(signButton.text, qsTr("Swap")) // verfy input and output panels verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, 0) compare(receivePanel.rawValue, "0") // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.00015" waitForRendering(receivePanel) formValuesChanged.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event with route that needs no approval const txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval txHasRouteNoApproval.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "") // verify loading state removed and data is displayed as expected on the Modal verify(root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, SQUtils.AmountsArithmetic.div( SQUtils.AmountsArithmetic.fromString(txHasRouteNoApproval.amountToReceive), SQUtils.AmountsArithmetic.fromNumber(1, root.swapAdaptor.toToken.decimals) ).toString()) // calculation needed for total fees let gasTimeEstimate = txHasRouteNoApproval.gasTimeEstimate let totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.swapAdaptor.fromToken.marketDetails.currencyPrice.amount let totalFees = root.swapAdaptor.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat compare(root.swapAdaptor.swapOutputData.totalFees, totalFees) compare(root.swapAdaptor.swapOutputData.approvalNeeded, false) compare(root.swapAdaptor.swapOutputData.hasError, false) verify(!errorTag.visible) verify(signButton.enabled) compare(signButton.text, qsTr("Swap")) // verfy input and output panels waitForRendering(receivePanel) verify(payPanel.valueValid) verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, root.swapStore.getWei2Eth(txHasRouteNoApproval.amountToReceive, root.swapAdaptor.toToken.decimals)) compare(receivePanel.rawValue, SQUtils.AmountsArithmetic.times( SQUtils.AmountsArithmetic.fromString(root.swapAdaptor.swapOutputData.toTokenAmount), SQUtils.AmountsArithmetic.fromNumber(1, root.swapAdaptor.toToken.decimals) ).toFixed()) // edit some params to retry swap root.swapFormData.fromTokenAmount = "0.012" waitForRendering(receivePanel) formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event with route that needs no approval let txRoutes2 = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded txRoutes2.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes2, "", "") // verify loading state removed and data ius displayed as expected on the Modal verify(root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, SQUtils.AmountsArithmetic.div( SQUtils.AmountsArithmetic.fromString(txRoutes2.amountToReceive), SQUtils.AmountsArithmetic.fromNumber(1, root.swapAdaptor.toToken.decimals)).toString()) // calculation needed for total fees gasTimeEstimate = txRoutes2.gasTimeEstimate totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.swapAdaptor.fromToken.marketDetails.currencyPrice.amount totalFees = root.swapAdaptor.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat compare(root.swapAdaptor.swapOutputData.totalFees, totalFees) compare(root.swapAdaptor.swapOutputData.approvalNeeded, true) compare(root.swapAdaptor.swapOutputData.hasError, false) verify(!errorTag.visible) verify(signButton.enabled) compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol)) // verfy input and output panels waitForRendering(receivePanel) verify(payPanel.valueValid) verify(!payPanel.mainInputLoading) verify(!payPanel.bottomTextLoading) verify(!receivePanel.mainInputLoading) verify(!receivePanel.bottomTextLoading) verify(!receivePanel.interactive) compare(receivePanel.selectedHoldingId, root.swapFormData.toTokenKey) compare(receivePanel.value, root.swapStore.getWei2Eth(txRoutes2.amountToReceive, root.swapAdaptor.toToken.decimals)) compare(receivePanel.rawValue, SQUtils.AmountsArithmetic.times( SQUtils.AmountsArithmetic.fromString(root.swapAdaptor.swapOutputData.toTokenAmount), SQUtils.AmountsArithmetic.fromNumber(1, root.swapAdaptor.toToken.decimals) ).toFixed()) } function test_modal_pay_input_default() { // Launch popup launchAndVerfyModal() const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const amountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!amountToSendInput) const bottomItemText = findChild(payPanel, "bottomItemText") verify(!!bottomItemText) const holdingSelector = findChild(payPanel, "holdingSelector") verify(!!holdingSelector) const maxTagButton = findChild(payPanel, "maxTagButton") verify(!!maxTagButton) const tokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText") verify(!!tokenSelectorContentItemText) waitForRendering(controlUnderTest.contentItem) // check default states for the from input selector compare(amountToSendInput.caption, qsTr("Pay")) verify(amountToSendInput.interactive) compare(amountToSendInput.text, "") verify(amountToSendInput.cursorVisible) compare(amountToSendInput.placeholderText, LocaleUtils.numberToLocaleString(0)) compare(bottomItemText.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(0, root.swapAdaptor.currencyStore.currentCurrency)) compare(holdingSelector.currentTokensKey, "") compare(tokenSelectorContentItemText.text, qsTr("Select asset")) verify(!maxTagButton.visible) compare(payPanel.selectedHoldingId, "") compare(payPanel.value, 0) compare(payPanel.rawValue, "0") verify(!payPanel.valueValid) closeAndVerfyModal() } function test_modal_pay_input_presetValues() { // try setting value before popup is launched and check values let valueToExchange = 0.001 let valueToExchangeString = valueToExchange.toString() root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId root.swapFormData.fromTokensKey = "ETH" root.swapFormData.fromTokenAmount = valueToExchangeString let expectedToken = SQUtils.ModelUtils.getByKey(root.tokenSelectorAdaptor.outputAssetsModel, "tokensKey", "ETH") // Launch popup launchAndVerfyModal() waitForItemPolished(controlUnderTest.contentItem) const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) waitForRendering(payPanel) const amountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!amountToSendInput) const bottomItemText = findChild(payPanel, "bottomItemText") verify(!!bottomItemText) const holdingSelector = findChild(payPanel, "holdingSelector") verify(!!holdingSelector) const maxTagButton = findChild(payPanel, "maxTagButton") verify(!!maxTagButton) const tokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText") verify(!!tokenSelectorContentItemText) const tokenSelectorIcon = findChild(payPanel, "tokenSelectorIcon") verify(!!tokenSelectorIcon) compare(amountToSendInput.caption, qsTr("Pay")) verify(amountToSendInput.interactive) tryCompare(amountToSendInput, "text", valueToExchangeString) compare(amountToSendInput.placeholderText, LocaleUtils.numberToLocaleString(0)) tryCompare(amountToSendInput, "cursorVisible", true) tryCompare(bottomItemText, "text", root.swapAdaptor.currencyStore.formatCurrencyAmount(valueToExchange * expectedToken.marketDetails.currencyPrice.amount, root.swapAdaptor.currencyStore.currentCurrency)) compare(holdingSelector.currentTokensKey, expectedToken.tokensKey) tryCompare(tokenSelectorContentItemText, "text", expectedToken.symbol) compare(tokenSelectorIcon.image.source, Constants.tokenIcon(expectedToken.symbol)) verify(tokenSelectorIcon.visible) verify(maxTagButton.visible) compare(maxTagButton.text, qsTr("Max. %1").arg(expectedToken.currentBalance === 0 ? "0" : root.swapAdaptor.currencyStore.formatCurrencyAmount(WalletUtils.calculateMaxSafeSendAmount(expectedToken.currentBalance, expectedToken.symbol), expectedToken.symbol, {noSymbol: true}))) compare(payPanel.selectedHoldingId, expectedToken.symbol) compare(payPanel.value, valueToExchange) compare(payPanel.rawValue, SQUtils.AmountsArithmetic.fromNumber(valueToExchangeString, expectedToken.decimals).toString()) tryCompare(payPanel, "valueValid", expectedToken.currentBalance > 0) closeAndVerfyModal() } function test_modal_pay_input_wrong_value_1() { let invalidValues = ["ABC", "0.0.010201", "12PASA", "100,9.01"] for (let i =0; i 0 ? maxPossibleValue.toLocaleString(Qt.locale(), 'f', -128) : "") tryCompare(bottomItemText, "text", root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue * expectedToken.marketDetails.currencyPrice.amount, root.swapAdaptor.currencyStore.currentCurrency)) closeAndVerfyModal() } function test_modal_pay_input_switching_accounts() { // test with pay value being set and not set let payValuesToTestWith = ["", "0.2"] for (let index = 0; index < payValuesToTestWith.length; index++) { let valueToExchangeString = payValuesToTestWith[index] let valueToExchange = Number(valueToExchangeString) // Asset chosen but no pay value set state ------------------------------------------------------------------------------- root.swapFormData.fromTokenAmount = valueToExchangeString root.swapFormData.selectedAccountAddress = swapAdaptor.nonWatchAccounts.get(0).address root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId root.swapFormData.fromTokensKey = "ETH" // Launch popup launchAndVerfyModal() const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const maxTagButton = findChild(payPanel, "maxTagButton") verify(!!maxTagButton) const amountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!amountToSendInput) const errorTag = findChild(controlUnderTest, "errorTag") verify(!!errorTag) for (let i=0; i< root.swapAdaptor.nonWatchAccounts.count; i++) { root.swapFormData.selectedAccountAddress = root.swapAdaptor.nonWatchAccounts.get(i).address waitForItemPolished(controlUnderTest.contentItem) let expectedToken = SQUtils.ModelUtils.getByKey(root.tokenSelectorAdaptor.outputAssetsModel, "tokensKey", "ETH") // check states for the pay input selector tryCompare(maxTagButton, "visible", true) let maxPossibleValue = WalletUtils.calculateMaxSafeSendAmount(expectedToken.currentBalance, expectedToken.symbol) tryCompare(maxTagButton, "text", qsTr("Max. %1").arg(maxPossibleValue === 0 ? Qt.locale().zeroDigit : root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue, expectedToken.symbol, {noSymbol: true}))) compare(payPanel.selectedHoldingId, expectedToken.symbol) tryCompare(payPanel, "valueValid", !!valueToExchangeString && valueToExchange <= maxPossibleValue) tryCompare(payPanel, "value", valueToExchange) compare(payPanel.rawValue, !!valueToExchangeString ? SQUtils.AmountsArithmetic.fromNumber(valueToExchangeString, expectedToken.decimals).toString(): "0") // check if tag is visible in case amount entered to exchange is greater than max balance to send let amountEnteredGreaterThanMaxBalance = valueToExchange > maxPossibleValue let errortext = amountEnteredGreaterThanMaxBalance ? qsTr("Insufficient funds for swap"): qsTr("An error has occured, please try again") compare(errorTag.visible, amountEnteredGreaterThanMaxBalance) compare(errorTag.text, root.swapAdaptor.errorMessage) compare(errorTag.buttonText, root.swapAdaptor.isTokenBalanceInsufficient ? qsTr("Buy crypto") : qsTr("Buy ETH")) compare(errorTag.buttonVisible, amountEnteredGreaterThanMaxBalance) } closeAndVerfyModal() } } function test_modal_exchange_button_enabled_state_data() { return [ {fromToken: "", fromTokenAmount: "", toToken: "", toTokenAmount: ""}, {fromToken: "", fromTokenAmount: "", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "100", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "STT", toTokenAmount: "50"}, {fromToken: "ETH", fromTokenAmount: "100", toToken: "STT", toTokenAmount: "50"}, {fromToken: "", fromTokenAmount: "", toToken: "", toTokenAmount: "50"}, {fromToken: "", fromTokenAmount: "100", toToken: "", toTokenAmount: ""} ] } function test_modal_exchange_button_enabled_state(data) { const swapExchangeButton = findChild(controlUnderTest, "swapExchangeButton") verify(!!swapExchangeButton) root.swapFormData.fromTokensKey = data.fromToken root.swapFormData.fromTokenAmount = data.fromTokenAmount root.swapFormData.toTokenKey = data.toToken root.swapFormData.toTokenAmount = data.toTokenAmount tryCompare(swapExchangeButton, "enabled", !!data.fromToken || !!data.toToken) } function test_modal_exchange_button_default_state_data() { return [ {fromToken: "", fromTokenAmount: "", toToken: "", toTokenAmount: ""}, {fromToken: "", fromTokenAmount: "", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "100", toToken: "STT", toTokenAmount: ""}, {fromToken: "ETH", fromTokenAmount: "", toToken: "STT", toTokenAmount: "50"}, {fromToken: "ETH", fromTokenAmount: "100", toToken: "STT", toTokenAmount: "50"}, {fromToken: "", fromTokenAmount: "", toToken: "", toTokenAmount: "50"}, {fromToken: "", fromTokenAmount: "100", toToken: "", toTokenAmount: ""} ] } function test_modal_exchange_button_default_state(data) { const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const receivePanel = findChild(controlUnderTest, "receivePanel") verify(!!receivePanel) const swapExchangeButton = findChild(controlUnderTest, "swapExchangeButton") verify(!!swapExchangeButton) const payAmountToSendInput = findChild(payPanel, "amountToSendInput") verify(!!payAmountToSendInput) const payBottomItemText = findChild(payPanel, "bottomItemText") verify(!!payBottomItemText) const maxTagButton = findChild(payPanel, "maxTagButton") verify(!!maxTagButton) const receiveAmountToSendInput = findChild(receivePanel, "amountToSendInput") verify(!!receiveAmountToSendInput) const receiveBottomItemText = findChild(receivePanel, "bottomItemText") verify(!!receiveBottomItemText) root.swapAdaptor.reset() // set network and address by default same root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId root.swapFormData.selectedAccountAddress = root.swapAdaptor.nonWatchAccounts.get(0).address root.swapFormData.fromTokensKey = data.fromToken root.swapFormData.fromTokenAmount = data.fromTokenAmount root.swapFormData.toTokenKey = data.toToken root.swapFormData.toTokenAmount = data.toTokenAmount let expectedFromTokenIcon = !!root.swapAdaptor.fromToken && !!root.swapAdaptor.fromToken.symbol ? Constants.tokenIcon(root.swapAdaptor.fromToken.symbol): "" let expectedToTokenIcon = !!root.swapAdaptor.toToken && !!root.swapAdaptor.toToken.symbol ? Constants.tokenIcon(root.swapAdaptor.toToken.symbol): "" // Launch popup launchAndVerfyModal() waitForRendering(payPanel) waitForRendering(receivePanel) let paytokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText") verify(!!paytokenSelectorContentItemText) let paytokenSelectorIcon = findChild(payPanel, "tokenSelectorIcon") compare(!!data.fromToken , !!paytokenSelectorIcon) let receivetokenSelectorContentItemText = findChild(receivePanel, "tokenSelectorContentItemText") verify(!!receivetokenSelectorContentItemText) let receivetokenSelectorIcon = findChild(receivePanel, "tokenSelectorIcon") compare(!!data.toToken, !!receivetokenSelectorIcon) // verify pay values compare(payPanel.tokenKey, data.fromToken) compare(payPanel.tokenAmount, data.fromTokenAmount) verify(payAmountToSendInput.cursorVisible) compare(paytokenSelectorContentItemText.text, !!root.swapFormData.fromTokensKey ? root.swapFormData.fromTokensKey : qsTr("Select asset")) compare(!!data.fromToken , !!paytokenSelectorIcon) if(!!paytokenSelectorIcon) { compare(paytokenSelectorIcon.image.source, expectedFromTokenIcon) } verify(!!data.fromToken ? maxTagButton.visible: !maxTagButton.visible) // verify receive values compare(receivePanel.tokenKey, data.toToken) compare(receivePanel.tokenAmount, data.toTokenAmount) verify(!receiveAmountToSendInput.cursorVisible) compare(receivetokenSelectorContentItemText.text, !!root.swapFormData.toTokenKey ? root.swapFormData.toTokenKey : qsTr("Select asset")) if(!!receivetokenSelectorIcon) { compare(receivetokenSelectorIcon.image.source, expectedToTokenIcon) } // click exchange button swapExchangeButton.clicked() waitForRendering(payPanel) waitForRendering(receivePanel) // verify form values compare(root.swapFormData.fromTokensKey, data.toToken) compare(root.swapFormData.fromTokenAmount, data.toTokenAmount) compare(root.swapFormData.toTokenKey, data.fromToken) compare(root.swapFormData.toTokenAmount, data.fromTokenAmount) paytokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText") verify(!!paytokenSelectorContentItemText) paytokenSelectorIcon = findChild(payPanel, "tokenSelectorIcon") compare(!!root.swapFormData.fromTokensKey , !!paytokenSelectorIcon) receivetokenSelectorContentItemText = findChild(receivePanel, "tokenSelectorContentItemText") verify(!!receivetokenSelectorContentItemText) receivetokenSelectorIcon = findChild(receivePanel, "tokenSelectorIcon") compare(!!root.swapFormData.toTokenKey, !!receivetokenSelectorIcon) // verify pay values compare(payPanel.tokenKey, data.toToken) compare(payPanel.tokenAmount, data.toTokenAmount) verify(payAmountToSendInput.cursorVisible) compare(paytokenSelectorContentItemText.text, !!data.toToken ? data.toToken : qsTr("Select asset")) if(!!paytokenSelectorIcon) { compare(paytokenSelectorIcon.image.source, expectedToTokenIcon) } verify(!!data.toToken ? maxTagButton.visible: !maxTagButton.visible) compare(maxTagButton.text, qsTr("Max. %1").arg(Qt.locale().zeroDigit)) compare(maxTagButton.type, (payAmountToSendInput.valid || !payAmountToSendInput.text) && maxTagButton.value > 0 ? StatusBaseButton.Type.Normal : StatusBaseButton.Type.Danger) // verify receive values compare(receivePanel.tokenKey, data.fromToken) compare(receivePanel.tokenAmount, data.fromTokenAmount) verify(!receiveAmountToSendInput.cursorVisible) compare(receivetokenSelectorContentItemText.text, !!data.fromToken ? data.fromToken : qsTr("Select asset")) if(!!receivetokenSelectorIcon) { compare(receivetokenSelectorIcon.image.source, expectedFromTokenIcon) } closeAndVerfyModal() } function test_approval_flow_button_states() { root.swapAdaptor.reset() // Launch popup launchAndVerfyModal() const maxFeesValue = findChild(controlUnderTest, "maxFeesValue") verify(!!maxFeesValue) const signButton = findChild(controlUnderTest, "signButton") verify(!!signButton) const errorTag = findChild(controlUnderTest, "errorTag") verify(!!errorTag) const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const receivePanel = findChild(controlUnderTest, "receivePanel") verify(!!receivePanel) // Check max fees values and sign button state when nothing is set compare(maxFeesValue.text, "--") verify(!signButton.interactive) verify(!errorTag.visible) // set input values in the form correctly root.swapFormData.fromTokensKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(0).key formValuesChanged.wait() root.swapFormData.toTokenKey = root.swapAdaptor.walletAssetsStore.walletTokensStore.plainTokensBySymbolModel.get(1).key root.swapFormData.fromTokenAmount = "0.001" formValuesChanged.wait() root.swapFormData.selectedNetworkChainId = root.swapAdaptor.filteredFlatNetworksModel.get(0).chainId formValuesChanged.wait() root.swapFormData.selectedAccountAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" formValuesChanged.wait() // wait for fetchSuggestedRoutes function to be called fetchSuggestedRoutesCalled.wait() // verify loading state was set and no errors currently verifyLoadingAndNoErrorsState(payPanel, receivePanel) // emit event with route that needs no approval let txRoutes = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded txRoutes.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txRoutes, "", "") // calculation needed for total fees let gasTimeEstimate = txRoutes.gasTimeEstimate let totalTokenFeesInFiat = gasTimeEstimate.totalTokenFees * root.swapAdaptor.fromToken.marketDetails.currencyPrice.amount let totalFees = root.swapAdaptor.currencyStore.getFiatValue(gasTimeEstimate.totalFeesInEth, Constants.ethToken) + totalTokenFeesInFiat let bestPath = SQUtils.ModelUtils.get(txRoutes.suggestedRoutes, 0, "route") // verify loading state removed and data is displayed as expected on the Modal verify(root.swapAdaptor.validSwapProposalReceived) verify(!root.swapAdaptor.swapProposalLoading) compare(root.swapAdaptor.swapOutputData.fromTokenAmount, "") compare(root.swapAdaptor.swapOutputData.toTokenAmount, SQUtils.AmountsArithmetic.div( SQUtils.AmountsArithmetic.fromString(txRoutes.amountToReceive), SQUtils.AmountsArithmetic.fromNumber(1, root.swapAdaptor.toToken.decimals)).toString()) compare(root.swapAdaptor.swapOutputData.totalFees, totalFees) compare(root.swapAdaptor.swapOutputData.hasError, false) compare(root.swapAdaptor.swapOutputData.estimatedTime, bestPath.estimatedTime) compare(root.swapAdaptor.swapOutputData.txProviderName, bestPath.bridgeName) compare(root.swapAdaptor.swapOutputData.approvalNeeded, true) compare(root.swapAdaptor.swapOutputData.approvalGasFees, bestPath.approvalGasFees.toString()) compare(root.swapAdaptor.swapOutputData.approvalAmountRequired, bestPath.approvalAmountRequired) compare(root.swapAdaptor.swapOutputData.approvalContractAddress, bestPath.approvalContractAddress) verify(!errorTag.visible) verify(signButton.enabled) verify(!signButton.loadingWithText) compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol)) // TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string. compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) // simulate user click on approve button and approval failed root.swapStore.transactionSent(root.swapAdaptor.uuid, root.swapFormData.selectedNetworkChainId, true, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "") verify(root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalSuccessful) verify(!errorTag.visible) verify(!signButton.interactive) verify(signButton.loadingWithText) compare(signButton.text, qsTr("Approving %1").arg(root.swapAdaptor.fromToken.symbol)) // TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string. compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) // simulate approval tx was unsuccessful root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Failed") verify(!root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalSuccessful) verify(!errorTag.visible) verify(signButton.enabled) verify(!signButton.loadingWithText) compare(signButton.text, qsTr("Approve %1").arg(root.swapAdaptor.fromToken.symbol)) // TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string. compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) // simulate user click on approve button and successful approval tx made signButton.clicked() root.swapStore.transactionSent(root.swapAdaptor.uuid, root.swapFormData.selectedNetworkChainId, true, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "") verify(root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalSuccessful) verify(!errorTag.visible) verify(!signButton.interactive) verify(signButton.loadingWithText) compare(signButton.text, qsTr("Approving %1").arg(root.swapAdaptor.fromToken.symbol)) // TODO: note that there is a loss of precision as the approvalGasFees is currently passes as float from the backend and not string. compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success") // simulate approval tx was successful signButton.clicked() root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success") verify(!root.swapAdaptor.approvalPending) verify(root.swapAdaptor.approvalSuccessful) verify(!errorTag.visible) verify(signButton.interactive) verify(!signButton.loadingWithText) compare(signButton.text, qsTr("Swap")) compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval txHasRouteNoApproval.uuid = root.swapAdaptor.uuid root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "") verify(!root.swapAdaptor.approvalPending) verify(root.swapAdaptor.approvalSuccessful) verify(!errorTag.visible) verify(signButton.enabled) verify(!signButton.loadingWithText) compare(signButton.text, qsTr("Swap")) compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount( root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.currencyStore.currentCurrency)) closeAndVerfyModal() } function test_modal_switching_networks_payPanel_data() { return [ {key: "ETH"}, {key: "aave"} ] } function test_modal_switching_networks_payPanel(data) { // try setting value before popup is launched and check values let valueToExchange = 1 let valueToExchangeString = valueToExchange.toString() root.swapFormData.selectedAccountAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" root.swapFormData.fromTokensKey = data.key root.swapFormData.fromTokenAmount = valueToExchangeString // Launch popup launchAndVerfyModal() const payPanel = findChild(controlUnderTest, "payPanel") verify(!!payPanel) const maxTagButton = findChild(payPanel, "maxTagButton") verify(!!maxTagButton) const networkComboBox = findChild(controlUnderTest, "networkFilter") verify(!!networkComboBox) const errorTag = findChild(controlUnderTest, "errorTag") verify(!!errorTag) for (let i=0; i { return balance.account.toLowerCase() === root.swapFormData.selectedAccountAddress.toLowerCase() && balance.chainId === root.swapFormData.selectedNetworkChainId }) let balance = SQUtils.AmountsArithmetic.toNumber( SQUtils.AmountsArithmetic.fromString(balanceEntry.balance), expectedToken.decimals) let maxPossibleValue = WalletUtils.calculateMaxSafeSendAmount(balance, expectedToken.symbol) compare(maxTagButton.text, qsTr("Max. %1").arg( maxPossibleValue === 0 ? "0" : root.swapAdaptor.currencyStore.formatCurrencyAmount(maxPossibleValue, expectedToken.symbol, {noSymbol: true}))) compare(payPanel.selectedHoldingId.toLowerCase(), expectedToken.symbol.toLowerCase()) compare(payPanel.valueValid, valueToExchange <= maxPossibleValue) tryCompare(payPanel, "rawValue", SQUtils.AmountsArithmetic.fromNumber(valueToExchangeString, expectedToken.decimals).toString()) compare(errorTag.visible, valueToExchange > maxPossibleValue) if(errorTag.visible) compare(errorTag.text, qsTr("Insufficient funds for swap")) compare(tokenSelectorContentItemText.text, expectedToken.symbol) } } closeAndVerfyModal() } function test_modal_switching_networks_receivePanel_data() { return [ {key: "aave"}, {key: "STT"} ] } function test_modal_switching_networks_receivePanel(data) { // try setting value before popup is launched and check values let valueToExchange = 1 let valueToExchangeString = valueToExchange.toString() root.swapFormData.selectedAccountAddress = "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" root.swapFormData.fromTokensKey = "ETH" root.swapFormData.fromTokenAmount = valueToExchangeString root.swapFormData.toTokenKey = data.key // Launch popup launchAndVerfyModal() const receivePanel = findChild(controlUnderTest, "receivePanel") verify(!!receivePanel) const networkComboBox = findChild(controlUnderTest, "networkFilter") verify(!!networkComboBox) for (let i=0; i