diff --git a/storybook/qmlTests/tests/tst_AssetSelector.qml b/storybook/qmlTests/tests/tst_AssetSelector.qml new file mode 100644 index 0000000000..1f4208883e --- /dev/null +++ b/storybook/qmlTests/tests/tst_AssetSelector.qml @@ -0,0 +1,238 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtTest 1.15 + +import AppLayouts.Wallet.controls 1.0 + +import utils 1.0 + +Item { + id: root + + width: 600 + height: 600 + + readonly property var assetsData: [ + { + tokensKey: "stt_key", + communityId: "", + name: "Status Test Token", + currencyBalanceAsString: "42,23 USD", + symbol: "STT", + iconSource: Constants.tokenIcon("STT"), + + balances: [ + { + balanceAsString: "0,56", + iconUrl: "network/Network=Ethereum" + } + ], + + sectionText: "My assets on Mainnet" + }, + { + tokensKey: "eth_key", + communityId: "", + name: "Ether", + currencyBalanceAsString: "4 276,86 USD", + symbol: "ETH", + iconSource: Constants.tokenIcon("ETH"), + + balances: [ + { + balanceAsString: "0,12", + iconUrl: "network/Network=Ethereum" + } + ], + + sectionText: "My assets on Mainnet" + }, + { + tokensKey: "dai_key", + communityId: "", + name: "Dai Stablecoin", + currencyBalanceAsString: "45,92 USD", + symbol: "DAI", + iconSource: Constants.tokenIcon("DAI"), + balances: [], + + sectionText: "Popular assets" + } + ] + + ListModel { + id: assetsModel + + Component.onCompleted: append(assetsData) + } + + Component { + id: selectorCmp + + AssetSelector { + id: selector + + anchors.centerIn: parent + model: assetsModel + + readonly property SignalSpy selectedSpy: SignalSpy { + target: selector + signalName: "selected" + } + } + } + + TestCase { + name: "AssetSelector" + when: windowShown + + function test_basic() { + const selector = createTemporaryObject(selectorCmp, root) + selector.nonInteractiveKey = "eth_key" + selector.sectionProperty = "sectionText" + + compare(selector.isSelected, false) + waitForRendering(selector) + + verify(selector.width > 0) + verify(selector.height > 0) + + mouseClick(selector) + + const panel = findChild(selector.Overlay.overlay, "searchableAssetsPanel") + compare(panel.model, selector.model) + compare(panel.nonInteractiveKey, selector.nonInteractiveKey) + compare(panel.sectionProperty, selector.sectionProperty) + } + + function test_basicSelection() { + const selector = createTemporaryObject(selectorCmp, root) + const button = selector.contentItem + + compare(selector.isSelected, false) + compare(button.selected, false) + waitForRendering(selector) + + // click to open popup + mouseClick(selector) + compare(selector.isSelected, false) + compare(button.selected, false) + + const listView = findChild(selector.Overlay.overlay, "assetsListView") + verify(listView) + + compare(listView.count, root.assetsData.length) + waitForRendering(listView) + + const delegate1 = listView.itemAtIndex(0) + const delegate2 = listView.itemAtIndex(1) + + verify(delegate1) + verify(delegate2) + + // click on delegate to select + mouseClick(delegate2) + compare(selector.isSelected, true) + compare(selector.selectedSpy.count, 1) + compare(selector.selectedSpy.signalArguments[0][0], "eth_key") + compare(button.selected, true) + compare(button.name, "ETH") + compare(button.icon, Constants.tokenIcon("ETH")) + + // popup should be closed, content not accessible + verify(!findChild(selector.Overlay.overlay, "searchableAssetsPanel")) + + // reopen popup + mouseClick(selector) + const panel = findChild(selector.Overlay.overlay, "searchableAssetsPanel") + verify(panel) + + compare(panel.highlightedKey, "eth_key") + compare(panel.nonInteractiveKey, "") + } + + function test_resetSelection() { + const selector = createTemporaryObject(selectorCmp, root) + const button = selector.contentItem + + compare(selector.isSelected, false) + compare(button.selected, false) + waitForRendering(selector) + + // click to open popup + mouseClick(selector) + + const listView = findChild(selector.Overlay.overlay, "assetsListView") + verify(listView) + + waitForRendering(listView) + const delegate2 = listView.itemAtIndex(1) + + verify(delegate2) + + // click on delegate to select + mouseClick(delegate2) + compare(selector.isSelected, true) + + // reset + selector.reset() + compare(selector.isSelected, false) + compare(button.selected, false) + + // reopen popup + mouseClick(selector) + const panel = findChild(selector.Overlay.overlay, "searchableAssetsPanel") + verify(panel) + + compare(panel.highlightedKey, "") + compare(panel.nonInteractiveKey, "") + } + + function test_customSelection() { + const selector = createTemporaryObject(selectorCmp, root) + const button = selector.contentItem + + compare(selector.isSelected, false) + waitForRendering(selector) + + const imageUrl = Constants.tokenIcon("DAI") + selector.setCustom("Custom", imageUrl, "custom_key") + + compare(selector.isSelected, true) + compare(selector.selectedSpy.count, 0) + compare(button.selected, true) + compare(button.name, "Custom") + compare(button.icon, Constants.tokenIcon("DAI")) + } + + function test_searchNotPersistent() { + const selector = createTemporaryObject(selectorCmp, root) + const button = selector.contentItem + + compare(selector.isSelected, false) + compare(button.selected, false) + waitForRendering(selector) + + // click to open popup + mouseClick(selector) + + const panel = findChild(selector.Overlay.overlay, "searchableAssetsPanel") + verify(panel) + + const searchBox = findChild(panel, "searchBox") + verify(searchBox) + + compare(searchBox.text, "") + searchBox.text = "seach string" + keyClick(Qt.Key_Escape) + + // click to re-open popup + mouseClick(selector) + { + const searchBox = findChild(panel, "searchBox") + verify(searchBox) + compare(searchBox.text, "") + } + } + } +} diff --git a/storybook/qmlTests/tests/tst_SearchableAssetsPanel.qml b/storybook/qmlTests/tests/tst_SearchableAssetsPanel.qml new file mode 100644 index 0000000000..7281a6ce4e --- /dev/null +++ b/storybook/qmlTests/tests/tst_SearchableAssetsPanel.qml @@ -0,0 +1,209 @@ +import QtQuick 2.15 +import QtTest 1.15 + +import AppLayouts.Wallet.panels 1.0 + +import Storybook 1.0 + +import utils 1.0 + +Item { + id: root + + width: 600 + height: 400 + + Component { + id: panelCmp + + SearchableAssetsPanel { + id: panel + + sectionProperty: "sectionText" + + readonly property SignalSpy selectedSpy: SignalSpy { + target: panel + signalName: "selected" + } + } + } + + readonly property var assetsData: [ + { + tokensKey: "stt_key", + communityId: "", + name: "Status Test Token", + currencyBalanceAsString: "42,23 USD", + symbol: "STT", + iconSource: Constants.tokenIcon("STT"), + balances: [ + { + balanceAsString: "0,56", + iconUrl: "network/Network=Ethereum" + }, + { + balanceAsString: "0,22", + iconUrl: "network/Network=Arbitrum" + }, + { + balanceAsString: "0,12", + iconUrl: "network/Network=Optimism" + } + ], + + sectionText: "" + }, + { + tokensKey: "dai_key", + communityId: "", + name: "Dai Stablecoin", + currencyBalanceAsString: "45,92 USD", + symbol: "DAI", + iconSource: Constants.tokenIcon("DAI"), + balances: [], + + sectionText: "Popular assets" + }, + { + tokensKey: "zrx_key", + communityId: "", + name: "0x", + currencyBalanceAsString: "41,22 USD", + symbol: "ZRX", + iconSource: Constants.tokenIcon("ZRX"), + balances: [], + + sectionText: "Popular assets" + } + ] + + ListModel { + id: model + + Component.onCompleted: append(root.assetsData) + } + + TestCase { + name: "SearchableAssetsPanel" + when: windowShown + + function test_sections() { + const control = createTemporaryObject(panelCmp, root, { model }) + + const listView = findChild(control, "assetsListView") + waitForRendering(listView) + + compare(listView.count, 3) + + const delegate1 = listView.itemAtIndex(0) + const delegate2 = listView.itemAtIndex(1) + const delegate3 = listView.itemAtIndex(2) + + verify(delegate1) + verify(delegate2) + verify(delegate3) + + compare(delegate1.ListView.section, "") + compare(delegate2.ListView.section, "Popular assets") + compare(delegate3.ListView.section, "Popular assets") + + const sectionDelegate = TestUtils.findTextItem(listView, "Popular assets") + verify(sectionDelegate) + + control.sectionProperty = "" + waitForRendering(listView) + + compare(delegate1.ListView.section, "") + compare(delegate2.ListView.section, "") + compare(delegate3.ListView.section, "") + } + + function test_search() { + const control = createTemporaryObject(panelCmp, root, { model }) + + const listView = findChild(control, "assetsListView") + waitForRendering(listView) + + const searchBox = findChild(control, "searchBox") + + { + searchBox.text = "Status" + waitForRendering(listView) + + compare(listView.count, 1) + const delegate1 = listView.itemAtIndex(0) + verify(delegate1) + compare(delegate1.name, "Status Test Token") + } + { + searchBox.text = "zrx" + waitForRendering(listView) + + compare(listView.count, 1) + const delegate1 = listView.itemAtIndex(0) + verify(delegate1) + compare(delegate1.name, "0x") + } + { + control.clearSearch() + waitForRendering(listView) + + compare(searchBox.text, "") + compare(listView.count, 3) + } + } + + function test_highlightedKey() { + const control = createTemporaryObject(panelCmp, root, { model }) + control.highlightedKey = "dai_key" + + const listView = findChild(control, "assetsListView") + waitForRendering(listView) + + compare(listView.count, 3) + + const delegate1 = listView.itemAtIndex(0) + const delegate2 = listView.itemAtIndex(1) + const delegate3 = listView.itemAtIndex(2) + + verify(delegate1) + verify(delegate2) + verify(delegate3) + + compare(delegate1.highlighted, false) + compare(delegate2.highlighted, true) + compare(delegate3.highlighted, false) + } + + function test_nonInteractiveKey() { + const control = createTemporaryObject(panelCmp, root, { model }) + control.nonInteractiveKey = "dai_key" + + const listView = findChild(control, "assetsListView") + waitForRendering(listView) + + compare(listView.count, 3) + + const delegate1 = listView.itemAtIndex(0) + const delegate2 = listView.itemAtIndex(1) + const delegate3 = listView.itemAtIndex(2) + + verify(delegate1) + verify(delegate2) + verify(delegate3) + + compare(delegate1.enabled, true) + compare(delegate2.enabled, false) + compare(delegate3.enabled, true) + + mouseClick(delegate1) + compare(control.selectedSpy.count, 1) + + mouseClick(delegate2) + compare(control.selectedSpy.count, 1) + + mouseClick(delegate3) + compare(control.selectedSpy.count, 2) + } + } +} diff --git a/storybook/qmlTests/tests/tst_TokenSelectorAssetDelegate.qml b/storybook/qmlTests/tests/tst_TokenSelectorAssetDelegate.qml new file mode 100644 index 0000000000..9ac42c8d6b --- /dev/null +++ b/storybook/qmlTests/tests/tst_TokenSelectorAssetDelegate.qml @@ -0,0 +1,133 @@ +import QtQuick 2.15 +import QtTest 1.15 + +import AppLayouts.Wallet.views 1.0 + +import Storybook 1.0 + +Item { + id: root + + width: 600 + height: 400 + + Component { + id: delegateCmp + + TokenSelectorAssetDelegate { + id: delegate + + name: "Ether" + symbol: "ETH" + currencyBalanceAsString: "42.02 USD" + iconSource: "" + width: 250 + + readonly property SignalSpy clickSpy: SignalSpy { + target: delegate + signalName: "clicked" + } + } + } + + ListModel { + id: balancesModel + + ListElement { + balanceAsString: "1234.50" + iconUrl: "network/Network=Ethereum" + } + ListElement { + balanceAsString: "33.52" + iconUrl: "network/Network=Arbitrum" + } + } + + TestCase { + name: "TokenSelectorAssetDelegate" + when: windowShown + + function test_elision() { + const control = createTemporaryObject(delegateCmp, root) + + const nameText = TestUtils.findTextItem(control, "Ether") + const symbolText = TestUtils.findTextItem(control, "ETH") + const balanceText = TestUtils.findTextItem(control, "42.02 USD") + + verify(nameText) + verify(symbolText) + verify(balanceText) + + verify(nameText.visible) + verify(symbolText.visible) + verify(balanceText.visible) + + waitForRendering(control) + + verify(nameText.width > 0) + verify(symbolText.width > 0) + verify(balanceText.width > 0) + + verify(!nameText.truncated) + verify(!symbolText.truncated) + verify(!balanceText.truncated) + + control.name = "Ether ".repeat(10) + + verify(nameText.truncated) + verify(!symbolText.truncated) + verify(!balanceText.truncated) + } + + function test_noBalances() { + const control = createTemporaryObject(delegateCmp, root) + + const list = findChild(control, "balancesListView") + compare(list.visible, false) + compare(list.count, 0) + compare(list.interactive, true) + + compare(control.opacity, 1) + control.enabled = false + verify(control.opacity < 1) + + mouseClick(control) + compare(control.clickSpy.count, 0) + + control.enabled = true + + mouseClick(control) + compare(control.clickSpy.count, 1) + } + + function test_withBalances() { + const control = createTemporaryObject(delegateCmp, root, + { balancesModel }) + + const list = findChild(control, "balancesListView") + waitForRendering(list) + + compare(list.visible, true) + compare(list.count, 2) + compare(list.interactive, true) + + mouseClick(control) + compare(control.clickSpy.count, 1) + + mouseClick(list) + compare(control.clickSpy.count, 2) + + control.balancesListInteractive = false + compare(list.interactive, false) + + const subBalanceText1 = TestUtils.findTextItem(control, "1234.50") + const subBalanceText2 = TestUtils.findTextItem(control, "33.52") + + verify(subBalanceText1) + verify(subBalanceText2) + + verify(subBalanceText1.visible) + verify(subBalanceText2.visible) + } + } +} diff --git a/storybook/qmlTests/tests/tst_TokenSelectorButton.qml b/storybook/qmlTests/tests/tst_TokenSelectorButton.qml new file mode 100644 index 0000000000..58d937ecdf --- /dev/null +++ b/storybook/qmlTests/tests/tst_TokenSelectorButton.qml @@ -0,0 +1,44 @@ +import QtQuick 2.15 +import QtTest 1.15 + +import AppLayouts.Wallet.controls 1.0 + +import Storybook 1.0 + +Item { + id: root + + width: 600 + height: 400 + + Component { + id: buttonCmp + + TokenSelectorButton { + name: "ETH" + icon: "" + } + } + + TestCase { + name: "TokenSelectorButton" + when: windowShown + + function test_notSelected() { + const button = createTemporaryObject(buttonCmp, root) + + verify(TestUtils.findTextItem(button, button.text)) + verify(!TestUtils.findTextItem(button, "ETH")) + verify(findChild(button, "notSelectedContent")) + } + + function test_selected() { + const button = createTemporaryObject(buttonCmp, root) + button.selected = true + + verify(!TestUtils.findTextItem(button, button.text)) + verify(TestUtils.findTextItem(button, "ETH")) + verify(findChild(button, "selectedContent")) + } + } +} diff --git a/ui/app/AppLayouts/Wallet/controls/TokenSelectorButton.qml b/ui/app/AppLayouts/Wallet/controls/TokenSelectorButton.qml index 792e0b81bf..73ae52245d 100644 --- a/ui/app/AppLayouts/Wallet/controls/TokenSelectorButton.qml +++ b/ui/app/AppLayouts/Wallet/controls/TokenSelectorButton.qml @@ -44,6 +44,8 @@ Control { id: notSelectedContent RowLayout { + objectName: "notSelectedContent" + spacing: 10 StatusBaseText { @@ -64,6 +66,8 @@ Control { id: selectedContent RowLayout { + objectName: "selectedContent" + spacing: Style.current.halfPadding StatusRoundedImage {