chore(dapps) implement service tests and basic workflow tests
Abstract WalletConnectSDK to make it testable Implement WC service pairing test Bring back DAppsWorkflow tests back to life and add a pair modal test Updates: #14927
This commit is contained in:
parent
e896267874
commit
145053e34f
|
@ -53,6 +53,14 @@ Item {
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
wcService: walletConnectService
|
wcService: walletConnectService
|
||||||
|
|
||||||
|
onDisplayToastMessage: (message, isErr) => {
|
||||||
|
if(isErr) {
|
||||||
|
console.log(`Storybook.displayToastMessage(${message}, "", "warning", false, Constants.ephemeralNotificationType.danger, "")`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(`Storybook.displayToastMessage(${message}, "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "")`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ColumnLayout {}
|
ColumnLayout {}
|
||||||
|
@ -83,6 +91,15 @@ Item {
|
||||||
// spacer
|
// spacer
|
||||||
ColumnLayout {}
|
ColumnLayout {}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
|
||||||
|
text: "Enable SDK"
|
||||||
|
checked: settings.enableSDK
|
||||||
|
onCheckedChanged: {
|
||||||
|
settings.enableSDK = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Text { text: "URI" }
|
Text { text: "URI" }
|
||||||
TextField {
|
TextField {
|
||||||
|
@ -170,7 +187,7 @@ Item {
|
||||||
id: walletConnectService
|
id: walletConnectService
|
||||||
|
|
||||||
wcSDK: WalletConnectSDK {
|
wcSDK: WalletConnectSDK {
|
||||||
active: true
|
active: settings.enableSDK
|
||||||
|
|
||||||
projectId: projectIdText.projectId
|
projectId: projectIdText.projectId
|
||||||
}
|
}
|
||||||
|
@ -246,6 +263,7 @@ Item {
|
||||||
property int testCase: d.noTestCase
|
property int testCase: d.noTestCase
|
||||||
property string pairUri: ""
|
property string pairUri: ""
|
||||||
property bool testNetworks: false
|
property bool testNetworks: false
|
||||||
|
property bool enableSDK: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
|
||||||
|
const requiredEventsJsonString = `["chainChanged", "accountsChanged"]`
|
||||||
|
const requiredMethodsJsonString = `["eth_sendTransaction","personal_sign"]`
|
||||||
|
const optionalNamespacesJsonString = `{
|
||||||
|
"eip155": {
|
||||||
|
"chains": [
|
||||||
|
"eip155:1",
|
||||||
|
"eip155:10"
|
||||||
|
],
|
||||||
|
"events": [
|
||||||
|
"chainChanged",
|
||||||
|
"accountsChanged",
|
||||||
|
"message",
|
||||||
|
"disconnect",
|
||||||
|
"connect"
|
||||||
|
],
|
||||||
|
"methods": [
|
||||||
|
"eth_sign",
|
||||||
|
"eth_signTransaction",
|
||||||
|
"eth_signTypedData",
|
||||||
|
"eth_signTypedData_v3",
|
||||||
|
"eth_signTypedData_v4",
|
||||||
|
"eth_sendTransaction"
|
||||||
|
],
|
||||||
|
"rpcMap": {
|
||||||
|
"1": "https://cloudflare-eth.com",
|
||||||
|
"10": "https://mainnet.optimism.io/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
const requiredNamespacesJsonString = `{
|
||||||
|
"eip155": {
|
||||||
|
"chains": [
|
||||||
|
"eip155:1"
|
||||||
|
],
|
||||||
|
"events": ${requiredEventsJsonString},
|
||||||
|
"methods": ${requiredMethodsJsonString},
|
||||||
|
"rpcMap": {
|
||||||
|
"1": "https://mainnet.io/123"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
const dappMetadataJsonString = `{
|
||||||
|
"description": "Test dApp description",
|
||||||
|
"icons": [
|
||||||
|
"https://test.com/icon.png"
|
||||||
|
],
|
||||||
|
"name": "TestApp",
|
||||||
|
"url": "https://app.test.org"
|
||||||
|
}`
|
||||||
|
|
||||||
|
function formatSessionProposal() {
|
||||||
|
return `{
|
||||||
|
"id": 1715976881734096,
|
||||||
|
"params": {
|
||||||
|
"expiryTimestamp": 1715977219,
|
||||||
|
"id": 1715976881734096,
|
||||||
|
"optionalNamespaces": ${optionalNamespacesJsonString},
|
||||||
|
"pairingTopic": "50fba141cdb5c015493c2907c46bacf9f7cbd7c8e3d4e97df891f18dddcff69c",
|
||||||
|
"proposer": {
|
||||||
|
"metadata": ${dappMetadataJsonString},
|
||||||
|
"publicKey": "095d9992ca0eb6081cabed26faf48919162fd70cc66d639f118a60507ae0463d"
|
||||||
|
},
|
||||||
|
"relays": [
|
||||||
|
{
|
||||||
|
"protocol": "irn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requiredNamespaces": ${requiredNamespacesJsonString}
|
||||||
|
},
|
||||||
|
"verifyContext": {
|
||||||
|
"verified": {
|
||||||
|
"origin": "https://app.test.org",
|
||||||
|
"validation": "UNKNOWN",
|
||||||
|
"verifyUrl": "https://verify.walletconnect.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBuildApprovedNamespacesResult(networksArray, accountsArray) {
|
||||||
|
let requiredChainsStr = networksArray.map(chainId => `"eip155:${chainId}"`).join(',')
|
||||||
|
let requiredAccountsStr = accountsArray.map(address => networksArray.map(chainId => `"eip155:${chainId}:${address}"`).join(',')).join(',')
|
||||||
|
return `{
|
||||||
|
"eip155": {
|
||||||
|
"chains": [${requiredChainsStr}],
|
||||||
|
"accounts": [${requiredAccountsStr}],
|
||||||
|
"events": ${requiredEventsJsonString},
|
||||||
|
"methods": ${requiredMethodsJsonString}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatApproveSessionResponse(networksArray, accountsArray) {
|
||||||
|
let chainsStr = networksArray.map(chainId => `"eip155:${chainId}"`).join(',')
|
||||||
|
let accountsStr = accountsArray.map(address => networksArray.map(chainId => `"eip155:${chainId}:${address}"`).join(',')).join(',')
|
||||||
|
return `{
|
||||||
|
"acknowledged": true,
|
||||||
|
"controller": "da4a87d5f0f54951afe870ebf020cf03f8a3522fbd219398c3fa159a37e16d54",
|
||||||
|
"expiry": 1716581732,
|
||||||
|
"namespaces": {
|
||||||
|
"eip155": {
|
||||||
|
"accounts": [${accountsStr}],
|
||||||
|
"chains": [${chainsStr}],
|
||||||
|
"events": ${requiredEventsJsonString},
|
||||||
|
"methods": ${requiredMethodsJsonString}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"optionalNamespaces": ${optionalNamespacesJsonString},
|
||||||
|
"pairingTopic": "50fba141cdb5c015493c2907c46bacf9f7cbd7c8e3d4e97df891f18dddcff69c",
|
||||||
|
"peer": {
|
||||||
|
"metadata": ${dappMetadataJsonString},
|
||||||
|
"publicKey": "095d9992ca0eb6081cabed26faf48919162fd70cc66d639f118a60507ae0463d"
|
||||||
|
},
|
||||||
|
"relay": {
|
||||||
|
"protocol": "irn"
|
||||||
|
},
|
||||||
|
"requiredNamespaces": ${requiredNamespacesJsonString},
|
||||||
|
"self": {
|
||||||
|
"metadata": {
|
||||||
|
"description": "Status Wallet",
|
||||||
|
"icons": [
|
||||||
|
"https://status.im/img/status-footer-logo.svg"
|
||||||
|
],
|
||||||
|
"name": "Status",
|
||||||
|
"url": "http://localhost"
|
||||||
|
},
|
||||||
|
"publicKey": "da4a87d5f0f54951afe870ebf020cf03f8a3522fbd219398c3fa159a37e16d54"
|
||||||
|
},
|
||||||
|
"topic": "e39e1f435a46b5ee6b31484d1751cfbc35be1275653af2ea340974a7592f1a19"
|
||||||
|
}`
|
||||||
|
}
|
|
@ -2,56 +2,286 @@ import QtQuick 2.15
|
||||||
import QtTest 1.15
|
import QtTest 1.15
|
||||||
|
|
||||||
import StatusQ 0.1 // See #10218
|
import StatusQ 0.1 // See #10218
|
||||||
|
import StatusQ.Core.Utils 0.1 // See #10218
|
||||||
|
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
import Storybook 1.0
|
import Storybook 1.0
|
||||||
|
|
||||||
//import AppLayouts.Wallet.panels 1.0
|
|
||||||
|
|
||||||
import AppLayouts.Wallet.services.dapps 1.0
|
import AppLayouts.Wallet.services.dapps 1.0
|
||||||
|
import AppLayouts.Profile.stores 1.0
|
||||||
|
import shared.stores 1.0
|
||||||
|
|
||||||
import QtQml.Models 2.15
|
import AppLayouts.Wallet.panels 1.0
|
||||||
|
|
||||||
|
import "helpers/wallet_connect.js" as Testing
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
width: 600
|
width: 600
|
||||||
height: 400
|
height: 400
|
||||||
|
|
||||||
// TODO: mock WalletConnectSDK
|
|
||||||
// Component {
|
|
||||||
// id: componentUnderTest
|
|
||||||
// DAppsWorkflow {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TestCase {
|
Component {
|
||||||
// name: "DAppsWorkflow"
|
id: sdkComponent
|
||||||
// when: windowShown
|
|
||||||
|
|
||||||
// property DAppsWorkflow controlUnderTest: null
|
WalletConnectSDKBase {
|
||||||
|
property bool sdkReady: true
|
||||||
|
|
||||||
// function init() {
|
property int pairCalled: 0
|
||||||
// controlUnderTest = createTemporaryObject(componentUnderTest, root)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function test_ClickToOpenAndClosePopup() {
|
getActiveSessions: function() {
|
||||||
// verify(!!controlUnderTest)
|
return []
|
||||||
// waitForRendering(controlUnderTest)
|
}
|
||||||
|
pair: function() {
|
||||||
|
pairCalled++
|
||||||
|
}
|
||||||
|
|
||||||
// mouseClick(controlUnderTest, Qt.LeftButton)
|
property var buildApprovedNamespacesCalls: []
|
||||||
// waitForRendering(controlUnderTest)
|
buildApprovedNamespaces: function(params, supportedNamespaces) {
|
||||||
|
buildApprovedNamespacesCalls.push({params, supportedNamespaces})
|
||||||
|
}
|
||||||
|
|
||||||
// let popup = findChild(controlUnderTest, "dappsPopup")
|
property var approveSessionCalls: []
|
||||||
// verify(!!popup)
|
approveSession: function(sessionProposalJson, approvedNamespaces) {
|
||||||
// verify(popup.opened)
|
approveSessionCalls.push({sessionProposalJson, approvedNamespaces})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// mouseClick(Overlay.overlay, Qt.LeftButton)
|
Component {
|
||||||
// waitForRendering(controlUnderTest)
|
id: serviceComponent
|
||||||
|
|
||||||
// verify(!popup.opened)
|
WalletConnectService {
|
||||||
// }
|
property var onApproveSessionResultTriggers: []
|
||||||
// }
|
onApproveSessionResult: function(session, error) {
|
||||||
|
onApproveSessionResultTriggers.push({session, error})
|
||||||
|
}
|
||||||
|
|
||||||
|
property var onDisplayToastMessageTriggers: []
|
||||||
|
onDisplayToastMessage: function(message, error) {
|
||||||
|
onDisplayToastMessageTriggers.push({message, error})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: dappsStoreComponent
|
||||||
|
|
||||||
|
DAppsStore {
|
||||||
|
signal dappsListReceived(string dappsJson)
|
||||||
|
|
||||||
|
// By default, return no dapps in store
|
||||||
|
function getDapps() {
|
||||||
|
dappsListReceived('[]')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
property var addWalletConnectSessionCalls: []
|
||||||
|
function addWalletConnectSession(sessionJson) {
|
||||||
|
addWalletConnectSessionCalls.push({sessionJson})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: walletStoreComponent
|
||||||
|
|
||||||
|
WalletStore {
|
||||||
|
readonly property ListModel flatNetworks: ListModel {
|
||||||
|
ListElement { chainId: 1 }
|
||||||
|
ListElement { chainId: 2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property ListModel accounts: ListModel {
|
||||||
|
ListElement { address: "0x1" }
|
||||||
|
ListElement { address: "0x2" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase {
|
||||||
|
id: walletConnectServiceTest
|
||||||
|
name: "WalletConnectService"
|
||||||
|
|
||||||
|
property WalletConnectService service: null
|
||||||
|
|
||||||
|
SignalSpy {
|
||||||
|
id: connectDAppSpy
|
||||||
|
target: walletConnectServiceTest.service
|
||||||
|
signalName: "connectDApp"
|
||||||
|
|
||||||
|
property var argPos: {
|
||||||
|
"dappChains": 0,
|
||||||
|
"sessionProposalJson": 1,
|
||||||
|
"availableNamespaces": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
let walletStore = createTemporaryObject(walletStoreComponent, root)
|
||||||
|
verify(!!walletStore)
|
||||||
|
let sdk = createTemporaryObject(sdkComponent, root, { projectId: "12ab" })
|
||||||
|
verify(!!sdk)
|
||||||
|
let store = createTemporaryObject(dappsStoreComponent, root)
|
||||||
|
verify(!!store)
|
||||||
|
service = createTemporaryObject(serviceComponent, root, {wcSDK: sdk, store: store, walletStore: walletStore})
|
||||||
|
verify(!!service)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
service.destroy()
|
||||||
|
connectDAppSpy.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_TestPairing() {
|
||||||
|
// All calls to SDK are expected as events to be made by the wallet connect SDK
|
||||||
|
let sdk = service.wcSDK
|
||||||
|
let walletStore = service.walletStore
|
||||||
|
let store = service.store
|
||||||
|
|
||||||
|
service.pair("wc:12ab@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=12ab")
|
||||||
|
compare(sdk.pairCalled, 1, "expected a call to sdk.pair")
|
||||||
|
|
||||||
|
sdk.sessionProposal(JSON.parse(Testing.formatSessionProposal()))
|
||||||
|
compare(sdk.buildApprovedNamespacesCalls.length, 1, "expected a call to sdk.buildApprovedNamespaces")
|
||||||
|
var args = sdk.buildApprovedNamespacesCalls[0]
|
||||||
|
verify(!!args.supportedNamespaces, "expected supportedNamespaces to be set")
|
||||||
|
let chainsForApproval = args.supportedNamespaces.eip155.chains
|
||||||
|
let networksArray = ModelUtils.modelToArray(walletStore.flatNetworks).map(entry => entry.chainId)
|
||||||
|
verify(networksArray.every(chainId => chainsForApproval.some(eip155Chain => eip155Chain === `eip155:${chainId}`)),
|
||||||
|
"expect all the networks to be present")
|
||||||
|
// We test here all accounts for one chain only, we have separate tests to validate that all accounts are present
|
||||||
|
let allAccountsForApproval = args.supportedNamespaces.eip155.accounts
|
||||||
|
let accountsArray = ModelUtils.modelToArray(walletStore.accounts).map(entry => entry.address)
|
||||||
|
verify(accountsArray.every(address => allAccountsForApproval.some(eip155Address => eip155Address === `eip155:${networksArray[0]}:${address}`)),
|
||||||
|
"expect at least all accounts for the first chain to be present"
|
||||||
|
)
|
||||||
|
|
||||||
|
let allApprovedNamespaces = JSON.parse(Testing.formatBuildApprovedNamespacesResult(networksArray, accountsArray))
|
||||||
|
sdk.buildApprovedNamespacesResult(allApprovedNamespaces, "")
|
||||||
|
compare(connectDAppSpy.count, 1, "expected a call to service.connectDApp")
|
||||||
|
let connectArgs = connectDAppSpy.signalArguments[0]
|
||||||
|
compare(connectArgs[connectDAppSpy.argPos.dappChains], networksArray, "expected all provided networks (walletStore.flatNetworks) for the dappChains")
|
||||||
|
verify(!!connectArgs[connectDAppSpy.argPos.sessionProposalJson], "expected sessionProposalJson to be set")
|
||||||
|
verify(!!connectArgs[connectDAppSpy.argPos.availableNamespaces], "expected availableNamespaces to be set")
|
||||||
|
|
||||||
|
let selectedAccount = walletStore.accounts.get(1)
|
||||||
|
service.approvePairSession(connectArgs[connectDAppSpy.argPos.sessionProposalJson], connectArgs[connectDAppSpy.argPos.dappChains], selectedAccount)
|
||||||
|
compare(sdk.buildApprovedNamespacesCalls.length, 2, "expected a call to sdk.buildApprovedNamespaces")
|
||||||
|
args = sdk.buildApprovedNamespacesCalls[1]
|
||||||
|
verify(!!args.supportedNamespaces, "expected supportedNamespaces to be set")
|
||||||
|
// We test here that only one account for all chains is provided
|
||||||
|
let accountsForApproval = args.supportedNamespaces.eip155.accounts
|
||||||
|
compare(accountsForApproval.length, networksArray.length, "expect only one account per chain")
|
||||||
|
compare(accountsForApproval[0], `eip155:${networksArray[0]}:${selectedAccount.address}`)
|
||||||
|
compare(accountsForApproval[1], `eip155:${networksArray[1]}:${selectedAccount.address}`)
|
||||||
|
|
||||||
|
let approvedNamespaces = JSON.parse(Testing.formatBuildApprovedNamespacesResult(networksArray, [selectedAccount.address]))
|
||||||
|
sdk.buildApprovedNamespacesResult(approvedNamespaces, "")
|
||||||
|
|
||||||
|
compare(sdk.approveSessionCalls.length, 1, "expected a call to sdk.approveSession")
|
||||||
|
verify(!!sdk.approveSessionCalls[0].sessionProposalJson, "expected sessionProposalJson to be set")
|
||||||
|
verify(!!sdk.approveSessionCalls[0].approvedNamespaces, "expected approvedNamespaces to be set")
|
||||||
|
|
||||||
|
let finalApprovedNamespaces = JSON.parse(Testing.formatApproveSessionResponse(networksArray, [selectedAccount.address]))
|
||||||
|
sdk.approveSessionResult(finalApprovedNamespaces, "")
|
||||||
|
verify(store.addWalletConnectSessionCalls.length === 1)
|
||||||
|
verify(store.addWalletConnectSessionCalls[0].sessionJson, "expected sessionJson to be set")
|
||||||
|
|
||||||
|
verify(service.onApproveSessionResultTriggers.length === 1)
|
||||||
|
verify(service.onApproveSessionResultTriggers[0].session, "expected session to be set")
|
||||||
|
|
||||||
|
compare(service.onDisplayToastMessageTriggers.length, 1, "expected a success message to be displayed")
|
||||||
|
verify(!service.onDisplayToastMessageTriggers[0].error, "expected no error")
|
||||||
|
verify(service.onDisplayToastMessageTriggers[0].message, "expected message to be set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: componentUnderTest
|
||||||
|
DAppsWorkflow {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase {
|
||||||
|
id: dappsWorkflowTest
|
||||||
|
name: "DAppsWorkflow"
|
||||||
|
when: windowShown
|
||||||
|
|
||||||
|
property DAppsWorkflow controlUnderTest: null
|
||||||
|
|
||||||
|
SignalSpy {
|
||||||
|
id: dappsListReadySpy
|
||||||
|
target: dappsWorkflowTest.controlUnderTest
|
||||||
|
signalName: "dappsListReady"
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalSpy {
|
||||||
|
id: pairWCReadySpy
|
||||||
|
target: dappsWorkflowTest.controlUnderTest
|
||||||
|
signalName: "pairWCReady"
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
let walletStore = createTemporaryObject(walletStoreComponent, root)
|
||||||
|
verify(!!walletStore)
|
||||||
|
let sdk = createTemporaryObject(sdkComponent, root, { projectId: "12ab" })
|
||||||
|
verify(!!sdk)
|
||||||
|
let store = createTemporaryObject(dappsStoreComponent, root)
|
||||||
|
verify(!!store)
|
||||||
|
let service = createTemporaryObject(serviceComponent, root, {wcSDK: sdk, store: store, walletStore: walletStore})
|
||||||
|
verify(!!service)
|
||||||
|
controlUnderTest = createTemporaryObject(componentUnderTest, root, {wcService: service})
|
||||||
|
verify(!!controlUnderTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
controlUnderTest.destroy()
|
||||||
|
dappsListReadySpy.reset()
|
||||||
|
pairWCReadySpy.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_OpenAndCloseDappList() {
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
|
||||||
|
compare(dappsListReadySpy.count, 0, "expected NO dappsListReady signal to be emitted")
|
||||||
|
mouseClick(controlUnderTest, Qt.LeftButton)
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
compare(dappsListReadySpy.count, 1, "expected dappsListReady signal to be emitted")
|
||||||
|
|
||||||
|
let popup = findChild(controlUnderTest, "dappsPopup")
|
||||||
|
verify(!!popup)
|
||||||
|
verify(popup.opened)
|
||||||
|
|
||||||
|
mouseClick(Overlay.overlay, Qt.LeftButton)
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
|
||||||
|
verify(!popup.opened)
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_OpenPairModal() {
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
|
||||||
|
mouseClick(controlUnderTest, Qt.LeftButton)
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
|
||||||
|
let popup = findChild(controlUnderTest, "dappsPopup")
|
||||||
|
verify(!!popup)
|
||||||
|
verify(popup.opened)
|
||||||
|
|
||||||
|
let connectButton = findChild(popup, "connectDappButton")
|
||||||
|
verify(!!connectButton)
|
||||||
|
|
||||||
|
verify(pairWCReadySpy.count === 0, "expected NO pairWCReady signal to be emitted")
|
||||||
|
mouseClick(connectButton, Qt.LeftButton)
|
||||||
|
waitForRendering(controlUnderTest)
|
||||||
|
verify(pairWCReadySpy.count === 1, "expected pairWCReady signal to be emitted")
|
||||||
|
|
||||||
|
let pairWCModal = findChild(controlUnderTest, "pairWCModal")
|
||||||
|
verify(!!pairWCModal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TestCase {
|
TestCase {
|
||||||
name: "ServiceHelpers"
|
name: "ServiceHelpers"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import shared.popups.walletconnect 1.0
|
||||||
import AppLayouts.Wallet.services.dapps 1.0
|
import AppLayouts.Wallet.services.dapps 1.0
|
||||||
|
|
||||||
import shared.stores 1.0
|
import shared.stores 1.0
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
ConnectedDappsButton {
|
ConnectedDappsButton {
|
||||||
id: root
|
id: root
|
||||||
|
@ -16,6 +17,7 @@ ConnectedDappsButton {
|
||||||
|
|
||||||
signal dappsListReady()
|
signal dappsListReady()
|
||||||
signal pairWCReady()
|
signal pairWCReady()
|
||||||
|
signal displayToastMessage(string message, bool error)
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
dappsListLoader.active = true
|
dappsListLoader.active = true
|
||||||
|
@ -138,5 +140,9 @@ ConnectedDappsButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onDisplayToastMessage(message, err) {
|
||||||
|
root.displayToastMessage(message, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,16 @@ Item {
|
||||||
enabled: !!Global.walletConnectService
|
enabled: !!Global.walletConnectService
|
||||||
|
|
||||||
wcService: Global.walletConnectService
|
wcService: Global.walletConnectService
|
||||||
|
|
||||||
|
onDisplayToastMessage: (message, isErr) => {
|
||||||
|
if (isErr) {
|
||||||
|
Global.displayToastMessage(message, "", "warning", false,
|
||||||
|
Constants.ephemeralNotificationType.danger, "")
|
||||||
|
} else {
|
||||||
|
Global.displayToastMessage(message, "", "checkmark-circle", false,
|
||||||
|
Constants.ephemeralNotificationType.success, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusButton {
|
StatusButton {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import utils 1.0
|
||||||
QObject {
|
QObject {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property WalletConnectSDK sdk
|
required property WalletConnectSDKBase sdk
|
||||||
required property DAppsStore store
|
required property DAppsStore store
|
||||||
|
|
||||||
readonly property alias dappsModel: d.dappsModel
|
readonly property alias dappsModel: d.dappsModel
|
||||||
|
|
|
@ -8,10 +8,9 @@ import QtWebChannel 1.15
|
||||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||||
import StatusQ.Components 0.1
|
import StatusQ.Components 0.1
|
||||||
|
|
||||||
Item {
|
WalletConnectSDKBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property string projectId
|
|
||||||
readonly property alias sdkReady: d.sdkReady
|
readonly property alias sdkReady: d.sdkReady
|
||||||
readonly property alias webEngineLoader: loader
|
readonly property alias webEngineLoader: loader
|
||||||
|
|
||||||
|
@ -21,66 +20,49 @@ Item {
|
||||||
implicitWidth: 1
|
implicitWidth: 1
|
||||||
implicitHeight: 1
|
implicitHeight: 1
|
||||||
|
|
||||||
signal statusChanged(string message)
|
|
||||||
signal sdkInit(bool success, var result)
|
|
||||||
signal pairResponse(bool success)
|
|
||||||
signal sessionProposal(var sessionProposal)
|
|
||||||
signal sessionProposalExpired()
|
|
||||||
signal buildApprovedNamespacesResult(var session, string error)
|
|
||||||
signal approveSessionResult(var approvedNamespaces, string error)
|
|
||||||
signal rejectSessionResult(string error)
|
|
||||||
signal sessionRequestEvent(var sessionRequest)
|
|
||||||
signal sessionRequestUserAnswerResult(bool accept, string error)
|
|
||||||
|
|
||||||
signal authRequest(var request)
|
|
||||||
signal authMessageFormated(string formatedMessage, string address)
|
|
||||||
signal authRequestUserAnswerResult(bool accept, string error)
|
|
||||||
|
|
||||||
signal sessionDelete(var topic, string error)
|
|
||||||
|
|
||||||
/// Generates \c pairResponse signal and expects to receive
|
/// Generates \c pairResponse signal and expects to receive
|
||||||
/// a \c sessionProposal signal with the sessionProposal object
|
/// a \c sessionProposal signal with the sessionProposal object
|
||||||
function pair(pairLink) {
|
pair: function(pairLink) {
|
||||||
wcCalls.pair(pairLink)
|
wcCalls.pair(pairLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPairings(callback) {
|
getPairings: function(callback) {
|
||||||
wcCalls.getPairings(callback)
|
wcCalls.getPairings(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveSessions(callback) {
|
getActiveSessions: function(callback) {
|
||||||
wcCalls.getActiveSessions(callback)
|
wcCalls.getActiveSessions(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnectSession(topic) {
|
disconnectSession: function(topic) {
|
||||||
wcCalls.disconnectSession(topic)
|
wcCalls.disconnectSession(topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnectPairing(topic) {
|
disconnectPairing: function(topic) {
|
||||||
wcCalls.disconnectPairing(topic)
|
wcCalls.disconnectPairing(topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ping(topic) {
|
ping: function(topic) {
|
||||||
wcCalls.ping(topic)
|
wcCalls.ping(topic)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildApprovedNamespaces(params, supportedNamespaces) {
|
buildApprovedNamespaces: function(params, supportedNamespaces) {
|
||||||
wcCalls.buildApprovedNamespaces(params, supportedNamespaces)
|
wcCalls.buildApprovedNamespaces(params, supportedNamespaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
function approveSession(sessionProposal, supportedNamespaces) {
|
approveSession: function(sessionProposal, supportedNamespaces) {
|
||||||
wcCalls.approveSession(sessionProposal, supportedNamespaces)
|
wcCalls.approveSession(sessionProposal, supportedNamespaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
function rejectSession(id) {
|
rejectSession: function(id) {
|
||||||
wcCalls.rejectSession(id)
|
wcCalls.rejectSession(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
function acceptSessionRequest(topic, id, signature) {
|
acceptSessionRequest: function(topic, id, signature) {
|
||||||
wcCalls.acceptSessionRequest(topic, id, signature)
|
wcCalls.acceptSessionRequest(topic, id, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
function rejectSessionRequest(topic, id, error) {
|
rejectSessionRequest: function(topic, id, error) {
|
||||||
wcCalls.rejectSessionRequest(topic, id, error)
|
wcCalls.rejectSessionRequest(topic, id, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
|
||||||
|
/// SDK requires a visible parent to embed WebEngineView
|
||||||
|
Item {
|
||||||
|
required property string projectId
|
||||||
|
|
||||||
|
signal statusChanged(string message)
|
||||||
|
signal sdkInit(bool success, var result)
|
||||||
|
signal pairResponse(bool success)
|
||||||
|
signal sessionProposal(var sessionProposal)
|
||||||
|
signal sessionProposalExpired()
|
||||||
|
signal buildApprovedNamespacesResult(var session, string error)
|
||||||
|
signal approveSessionResult(var approvedNamespaces, string error)
|
||||||
|
signal rejectSessionResult(string error)
|
||||||
|
signal sessionRequestEvent(var sessionRequest)
|
||||||
|
signal sessionRequestUserAnswerResult(bool accept, string error)
|
||||||
|
|
||||||
|
signal authRequest(var request)
|
||||||
|
signal authMessageFormated(string formatedMessage, string address)
|
||||||
|
signal authRequestUserAnswerResult(bool accept, string error)
|
||||||
|
|
||||||
|
signal sessionDelete(var topic, string error)
|
||||||
|
|
||||||
|
property var pair: function(pairLink) {
|
||||||
|
console.error("pair not implemented")
|
||||||
|
}
|
||||||
|
property var getPairings: function(callback) {
|
||||||
|
console.error("getPairings not implemented")
|
||||||
|
}
|
||||||
|
property var getActiveSessions: function(callback) {
|
||||||
|
console.error("getActiveSessions not implemented")
|
||||||
|
}
|
||||||
|
property var disconnectSession: function(topic) {
|
||||||
|
console.error("disconnectSession not implemented")
|
||||||
|
}
|
||||||
|
property var disconnectPairing: function(topic) {
|
||||||
|
console.error("disconnectPairing not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
property var ping: function(topic) {
|
||||||
|
console.error("ping not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
property var buildApprovedNamespaces: function(params, supportedNamespaces) {
|
||||||
|
console.error("buildApprovedNamespaces not implemented")
|
||||||
|
}
|
||||||
|
property var approveSession: function(sessionProposal, supportedNamespaces) {
|
||||||
|
console.error("approveSession not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
property var rejectSession: function(id) {
|
||||||
|
console.error("rejectSession not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
property var acceptSessionRequest: function(topic, id, signature) {
|
||||||
|
console.error("acceptSessionRequest not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
property var rejectSessionRequest: function(topic, id, error) {
|
||||||
|
console.error("rejectSessionRequest not implemented")
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,11 +14,11 @@ import utils 1.0
|
||||||
QObject {
|
QObject {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property WalletConnectSDK wcSDK
|
required property WalletConnectSDKBase wcSDK
|
||||||
required property DAppsStore store
|
required property DAppsStore store
|
||||||
required property WalletStore walletStore
|
required property WalletStore walletStore
|
||||||
|
|
||||||
readonly property alias dappsModel: d.dappsProvider.dappsModel
|
readonly property alias dappsModel: dappsProvider.dappsModel
|
||||||
|
|
||||||
readonly property var validAccounts: SortFilterProxyModel {
|
readonly property var validAccounts: SortFilterProxyModel {
|
||||||
sourceModel: walletStore.accounts
|
sourceModel: walletStore.accounts
|
||||||
|
@ -51,6 +51,7 @@ QObject {
|
||||||
|
|
||||||
signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces)
|
signal connectDApp(var dappChains, var sessionProposal, var approvedNamespaces)
|
||||||
signal approveSessionResult(var session, var error)
|
signal approveSessionResult(var session, var error)
|
||||||
|
signal displayToastMessage(string message, bool error)
|
||||||
|
|
||||||
readonly property Connections sdkConnections: Connections {
|
readonly property Connections sdkConnections: Connections {
|
||||||
target: wcSDK
|
target: wcSDK
|
||||||
|
@ -78,9 +79,6 @@ QObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onApproveSessionResult(session, err) {
|
function onApproveSessionResult(session, err) {
|
||||||
// Notify client
|
|
||||||
root.approveSessionResult(session, err)
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
// TODO #14676: handle the error
|
// TODO #14676: handle the error
|
||||||
console.error("Failed to approve session", err)
|
console.error("Failed to approve session", err)
|
||||||
|
@ -89,44 +87,42 @@ QObject {
|
||||||
|
|
||||||
// TODO #14754: implement custom dApp notification
|
// TODO #14754: implement custom dApp notification
|
||||||
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
||||||
Global.displayToastMessage(qsTr("Connected to %1 via WalletConnect").arg(app_url), "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "")
|
root.displayToastMessage(qsTr("Connected to %1 via WalletConnect").arg(app_url), false)
|
||||||
|
|
||||||
// Persist session
|
// Persist session
|
||||||
store.addWalletConnectSession(JSON.stringify(session))
|
store.addWalletConnectSession(JSON.stringify(session))
|
||||||
|
|
||||||
d.dappsProvider.updateDapps()
|
// Notify client
|
||||||
|
root.approveSessionResult(session, err)
|
||||||
|
|
||||||
|
dappsProvider.updateDapps()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRejectSessionResult(err) {
|
function onRejectSessionResult(err) {
|
||||||
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
||||||
if(err) {
|
if(err) {
|
||||||
Global.displayToastMessage(qsTr("Failed to reject connection request for %1").arg(app_url), "", "warning", false, Constants.ephemeralNotificationType.danger, "")
|
root.displayToastMessage(qsTr("Failed to reject connection request for %1").arg(app_url), true)
|
||||||
} else {
|
} else {
|
||||||
Global.displayToastMessage(qsTr("Connection request for %1 was rejected").arg(app_url), "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "")
|
root.displayToastMessage(qsTr("Connection request for %1 was rejected").arg(app_url), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSessionDelete(topic, err) {
|
function onSessionDelete(topic, err) {
|
||||||
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
let app_url = d.currentSessionProposal ? d.currentSessionProposal.params.proposer.metadata.url : "-"
|
||||||
if(err) {
|
if(err) {
|
||||||
Global.displayToastMessage(qsTr("Failed to disconnect from %1").arg(app_url), "", "warning", false, Constants.ephemeralNotificationType.danger, "")
|
root.displayToastMessage(qsTr("Failed to disconnect from %1").arg(app_url), true)
|
||||||
} else {
|
} else {
|
||||||
Global.displayToastMessage(qsTr("Disconnected from %1").arg(app_url), "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "")
|
root.displayToastMessage(qsTr("Disconnected from %1").arg(app_url), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
property var currentSessionProposal: null
|
property var currentSessionProposal: null
|
||||||
property var acceptedSessionProposal: null
|
property var acceptedSessionProposal: null
|
||||||
|
|
||||||
readonly property DAppsListProvider dappsProvider: DAppsListProvider {
|
|
||||||
sdk: root.wcSDK
|
|
||||||
store: root.store
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO #14676: use it to check if already paired
|
// TODO #14676: use it to check if already paired
|
||||||
function getPairingTopicFromPairingUrl(url)
|
function getPairingTopicFromPairingUrl(url)
|
||||||
{
|
{
|
||||||
|
@ -146,6 +142,13 @@ QObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
d.dappsProvider.updateDapps()
|
dappsProvider.updateDapps()
|
||||||
|
}
|
||||||
|
|
||||||
|
DAppsListProvider {
|
||||||
|
id: dappsProvider
|
||||||
|
|
||||||
|
sdk: root.wcSDK
|
||||||
|
store: root.store
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
WalletConnectSDKBase 1.0 WalletConnectSDKBase.qml
|
||||||
WalletConnectSDK 1.0 WalletConnectSDK.qml
|
WalletConnectSDK 1.0 WalletConnectSDK.qml
|
||||||
WalletConnectService 1.0 WalletConnectService.qml
|
WalletConnectService 1.0 WalletConnectService.qml
|
||||||
DAppsListProvider 1.0 DAppsListProvider.qml
|
DAppsListProvider 1.0 DAppsListProvider.qml
|
||||||
|
|
|
@ -95,6 +95,7 @@ Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusButton {
|
StatusButton {
|
||||||
|
objectName: "connectDappButton"
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: implicitHeight
|
Layout.preferredHeight: implicitHeight
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ import "PairWCModal"
|
||||||
StatusDialog {
|
StatusDialog {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
objectName: "pairWCModal"
|
||||||
|
|
||||||
width: 480
|
width: 480
|
||||||
implicitHeight: 633
|
implicitHeight: 633
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue