diff --git a/cypress.json b/cypress.json
index b5caa606e..4bf293805 100644
--- a/cypress.json
+++ b/cypress.json
@@ -6,6 +6,7 @@
"spec_configures_nodes.js",
"spec_devices.js",
"spec_ghost_machine.js",
+ "spec_rescan.js",
"spec_qr_signing.js",
"spec_wallet_send.js",
"spec_wallet_utxo.js",
diff --git a/cypress/integration/spec_devices.js b/cypress/integration/spec_devices.js
index e928f5cc9..07f455631 100644
--- a/cypress/integration/spec_devices.js
+++ b/cypress/integration/spec_devices.js
@@ -1,15 +1,26 @@
describe('Test adding different devices', () => {
before(() => {
- cy.viewport(1200,660)
- cy.visit('/')
Cypress.config('includeShadowDom', true)
})
// Keeps the session cookie alive, Cypress by default clears all cookies before each test
beforeEach(() => {
+ cy.viewport(1200,660)
+ cy.visit('/')
Cypress.Cookies.preserveOnce('session')
})
+ it('Filter devices', () => {
+ cy.get('#toggle_devices_list').click()
+ cy.get('#btn_new_device').click()
+ cy.contains('Select Your Device Type')
+ cy.get('#device-type-searchbar').type("Specter")
+ cy.get('#trezor_device_card').should('not.be.visible')
+ cy.get('#specter_device_card').should('be.visible')
+ cy.get('#specter_device_card').click()
+ cy.contains('Connect your Specter-DIY')
+ })
+
it('Electrum device', () => {
cy.get('#toggle_devices_list').click()
cy.get('#btn_new_device').click()
diff --git a/cypress/integration/spec_empty_specter_home.js b/cypress/integration/spec_empty_specter_home.js
index f731e1e9a..5ac14ed95 100644
--- a/cypress/integration/spec_empty_specter_home.js
+++ b/cypress/integration/spec_empty_specter_home.js
@@ -1,11 +1,12 @@
describe('Completely empty specter-home', () => {
- beforeEach(() => {
+ before(() => {
cy.task("clear:specter-home")
})
- it('Visits specter and clicks around', () => {
+
+ it('Click around on the welcome page', () => {
cy.viewport(1200,660)
- cy.visit('/')
+ cy.visit('/welcome/about')
cy.contains('Welcome to Specter Desktop')
cy.get('#node-switch-icon').click()
cy.get('[href="/nodes/node/default/"]').first().click()
@@ -16,28 +17,16 @@ describe('Completely empty specter-home', () => {
cy.contains('Authentication:')
cy.get('[href="/settings/hwi"]').click()
cy.contains('Hardware Devices Bridge')
- // Hidden in Cypress behind the price
- // cy.get('[href="/settings/tor"]').click()
- // cy.contains('Tor configurations')
+ cy.get('main').scrollTo('top')
+ cy.contains('Tor').click({ scrollBehavior: false })
+ cy.contains('Tor configurations')
cy.contains("Choose plugins")
cy.get('#btn_plugins').click()
cy.contains("Plugins in Production")
-
-
- })
-
- it('Creates a device in Specter', () => {
- cy.viewport(1200,660)
- cy.visit('/')
- cy.addDevice("Some Device")
- })
-
- it('Dummytest to enforce remove of device', () => {
- cy.viewport(1200,660)
- cy.visit('/')
})
})
+
diff --git a/cypress/integration/spec_ghost_machine.js b/cypress/integration/spec_ghost_machine.js
index e6b8c33cd..e9c39693d 100644
--- a/cypress/integration/spec_ghost_machine.js
+++ b/cypress/integration/spec_ghost_machine.js
@@ -2,26 +2,7 @@ describe('Ghost machine', () => {
it('Create a DIY device with ghost machine keys and a wallet', () => {
cy.viewport(1200,660)
cy.visit('/')
- // addDevice is creating a DIY device with ghost machine keys
- cy.addDevice("DIY ghost")
- cy.get('body').then(($body) => {
- if ($body.text().includes('Wallet ghost')) {
- cy.contains('Wallet ghost').click()
- cy.get('#btn_settings').click({"force": true})
- cy.get('#advanced_settings_tab_btn').click()
- cy.get('#delete_wallet').click()
- }
- })
- cy.get('#btn_new_wallet').click()
- cy.get('[href="./simple/"]').click()
- cy.get('#diy_ghost').click()
- cy.get('#wallet_name').type("Wallet ghost")
- cy.get('#keysform > .centered').click()
- cy.get('body').contains("New wallet was created successfully!")
- // Download PDF
- // unfortunately this results in weird effects in cypress run
- //cy.get('#pdf-wallet-download > img').click()
- cy.get('#btn_continue').click()
- cy.mine2wallet("btc")
+ cy.addDevice('DIY ghost', 'Specter-DIY', 'ghost_machine')
+ cy.addWallet('Ghost wallet', null, 'segwit', 'funded', 'btc')
})
})
diff --git a/cypress/integration/spec_plugins.js b/cypress/integration/spec_plugins.js
index dad1feba6..ef0dd4eb3 100644
--- a/cypress/integration/spec_plugins.js
+++ b/cypress/integration/spec_plugins.js
@@ -11,7 +11,7 @@ describe('Test plugins', () => {
it('Associate an address with a service', () => {
// choose address
- cy.selectWallet("Wallet ghost")
+ cy.selectWallet("Ghost wallet")
cy.get('main').contains('Addresses').click()
// Click on the first address
cy.contains('td', '#0').siblings().contains('bcrt').click()
@@ -24,7 +24,7 @@ describe('Test plugins', () => {
cy.contains("Admin password successfully updated")
// Choose address again
- cy.selectWallet("Wallet ghost")
+ cy.selectWallet("Ghost wallet")
cy.get('main').contains('Addresses').click()
cy.contains('td', '#0').siblings().contains('bcrt').click()
cy.get('#associate-btn').click()
diff --git a/cypress/integration/spec_qr_signing.js b/cypress/integration/spec_qr_signing.js
index 0d16b2355..e37c19678 100644
--- a/cypress/integration/spec_qr_signing.js
+++ b/cypress/integration/spec_qr_signing.js
@@ -12,7 +12,7 @@ describe('Test QR code signing flow', () => {
})
it('Message signing with Specter DIY', () => {
- cy.get('.side').contains('Wallet ghost').click()
+ cy.get('.side').contains('Ghost wallet').click()
cy.get('main').contains('Addresses').click()
// Click on the first address
cy.contains('td', '#0').siblings().contains('bcrt').click()
@@ -33,7 +33,7 @@ describe('Test QR code signing flow', () => {
cy.get('#diy_ghost_qr_sign_msg_btn').should('not.exist')
cy.get('#diy_ghost_usb_sign_msg_btn').should('exist')
cy.get('#page_overlay_popup_cancel_button').click()
- cy.contains("Wallet ghost").click()
+ cy.contains("Ghost wallet").click()
cy.get('main').contains('Addresses').click()
cy.contains('td', '#0').siblings().contains('bcrt').click()
cy.get('#msg-signing-btn').should('exist')
diff --git a/cypress/integration/spec_rescan.js b/cypress/integration/spec_rescan.js
new file mode 100644
index 000000000..0976949e1
--- /dev/null
+++ b/cypress/integration/spec_rescan.js
@@ -0,0 +1,29 @@
+describe('Test the UI related to a blockchain rescan', () => {
+ before(() => {
+ Cypress.config('includeShadowDom', true)
+ })
+
+ // Keeps the session cookie alive, Cypress by default clears all cookies before each test
+ beforeEach(() => {
+ cy.visit('/')
+ cy.viewport(1200,660)
+ Cypress.Cookies.preserveOnce('session')
+ })
+
+ it('Go to the rescan section from a fresh wallet', () => {
+ // Create a completely fresh wallet which is not receiving funds from the continous mining
+ cy.addDevice('Trezor hold', 'Trezor', 'hold_accident')
+ cy.addWallet('Fresh wallet', 'Trezor hold', 'segwit', false)
+ cy.get('#btn_transactions').click()
+ cy.get('#go-to-rescan-btn').click()
+ cy.get('#blockchain-rescan').should('be.visible')
+ // TODO: Do we keep this wallet and this device or teardown?
+ })
+
+ it('Check that there is no button for a used wallet', () => {
+ // Only works if the ghost wallet was created with funded option
+ cy.selectWallet('Ghost wallet')
+ cy.get('#rescan-hint > p').should('not.be.visible')
+ cy.get('#rescan-hint > .btn').should('not.be.visible')
+ })
+})
\ No newline at end of file
diff --git a/cypress/integration/spec_wallet_utxo.js b/cypress/integration/spec_wallet_utxo.js
index 0e53c1467..dd60da4d0 100644
--- a/cypress/integration/spec_wallet_utxo.js
+++ b/cypress/integration/spec_wallet_utxo.js
@@ -98,7 +98,7 @@ describe('Test the actions in UTXO list', () => {
it('Managing unsigned transactions', () => {
// Make an unsigned tx
- cy.get('#address_0').type("bcrt1qvtdx75y4554ngrq6aff3xdqnvjhmct5wck95qs") // address from "Wallet ghost"
+ cy.get('#address_0').type("bcrt1qvtdx75y4554ngrq6aff3xdqnvjhmct5wck95qs") // address from "Ghost wallet"
cy.get('#send_max_0').click()
cy.get('#create_psbt_btn').click()
// Check the labeling of the unsigned UTXO
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index c106b73e2..6b1f5835c 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -26,7 +26,7 @@
import 'cypress-wait-until';
-Cypress.Commands.add("addDevice", (name) => {
+Cypress.Commands.add("addDevice", (name, device_type, mnemonic) => {
cy.get('body').then(($body) => {
if ($body.text().includes(name)) {
cy.get('#toggle_devices_list').click()
@@ -38,25 +38,23 @@ Cypress.Commands.add("addDevice", (name) => {
cy.get('#toggle_devices_list').click()
}
cy.get('#btn_new_device').click()
- // Creating a Device
- cy.contains('Select Your Device Type')
- cy.get('#trezor_device_card')
- cy.get('#device-type-searchbar').type("specter")
- cy.contains('Select Your Device Type')
- cy.get('#trezor_device_card').should('not.have.class', 'disabled')
- cy.get('#specter_device_card').click()
- cy.get('h2 > input').type(name)
- cy.go('back')
- cy.get('#device-type-container > .note').click()
+ cy.contains('Manual configuration').click()
cy.get('#device_name').type(name)
- cy.get('#device_type').select("Specter-DIY")
- cy.get('#txt').type("[8c24a510/84h/1h/0h]vpub5Y24kG7ZrCFRkRnHia2sdnt5N7MmsrNry1jMrP8XptMEcZZqkjQA6bc1f52RGiEoJmdy1Vk9Qck9tAL1ohKvuq3oFXe3ADVse6UiTHzuyKx")
- cy.get('#txt').type("\n[8c24a510/49h/1h/0h]upub5DCn7wm4SgVmzmtdoi8DVVfxhBJkqL1L6mmKHNgVky1Fj5VyBxV6NzKD957sr5fWXkY5y8THtqSVWWpjLnomBYw4iXpxaPbkXg5Gn6s5tQf")
- cy.get('#txt').type("\n[8c24a510/48h/1h/0h/1h]Upub5S2BXfT5rv2bc2i4Hr8NaBzcu243ztEMJ7LUDK4A9UKRtVmr9EFNdNdPz8rAXQnZDeAoHA8KcR7grVjREWKpBr69bev4rkvxytLZ6fN3sUv")
- cy.get('#txt').type("\n[8c24a510/48h/1h/0h/2h]Vpub5krSqL811ba5VJdUoP42TFmfRkAaR6h4uxdDThCvDd24PR5gXWPHCvASLbEKevdQQjGx3i1WG7ueEARb8Hpo2u4HikY3wnvwvF1VSakkjew")
- cy.get('#cold_device > [type="submit"]').click()
- cy.get('#toggle_devices_list').click()
- cy.get('#devices_list > .item > div').contains(name)
+ // Device types are the names to select from, such as Trezor, Specter-DIY or Electrum
+ cy.get('#device_type').select(device_type)
+ if (mnemonic === "ghost_machine" || mnemonic === null) {
+ cy.get('#txt').type("[8c24a510/84h/1h/0h]vpub5Y24kG7ZrCFRkRnHia2sdnt5N7MmsrNry1jMrP8XptMEcZZqkjQA6bc1f52RGiEoJmdy1Vk9Qck9tAL1ohKvuq3oFXe3ADVse6UiTHzuyKx")
+ cy.get('#txt').type("\n[8c24a510/49h/1h/0h]upub5DCn7wm4SgVmzmtdoi8DVVfxhBJkqL1L6mmKHNgVky1Fj5VyBxV6NzKD957sr5fWXkY5y8THtqSVWWpjLnomBYw4iXpxaPbkXg5Gn6s5tQf")
+ cy.get('#txt').type("\n[8c24a510/48h/1h/0h/1h]Upub5S2BXfT5rv2bc2i4Hr8NaBzcu243ztEMJ7LUDK4A9UKRtVmr9EFNdNdPz8rAXQnZDeAoHA8KcR7grVjREWKpBr69bev4rkvxytLZ6fN3sUv")
+ cy.get('#txt').type("\n[8c24a510/48h/1h/0h/2h]Vpub5krSqL811ba5VJdUoP42TFmfRkAaR6h4uxdDThCvDd24PR5gXWPHCvASLbEKevdQQjGx3i1WG7ueEARb8Hpo2u4HikY3wnvwvF1VSakkjew")
+ }
+ if (mnemonic === "hold_accident") {
+ cy.get('#txt').type("[ccf2e5c3/84h/1h/0h]vpub5YkPJgRQsev79YZM1NRDKJWDjLFcD2xSFAt6LehC5iiMMqQgMHyCFQzwsu16Rx9rBpXZVXPjWAxybuCpsayaw8qCDZtjwH9vifJ7WiQkHwu")
+ cy.get('#txt').type("\n[ccf2e5c3/49h/1h/0h]upub5DH3pJxqyFKA9Xu8mbKie67UvJ5VWsDDtEg2YR98Yy99UGFNnBa6VSk36zW1ZWTrbYa1Nk6zrxSvzL2hdzjbRUatmwaVUPPYzyEniauECJy")
+ cy.get('#txt').type("\n[ccf2e5c3/48h/1h/0h/1h]Upub5RyWnpxermQY5L7knm9gDPMQGcFKqat9pDKxhNGoVQHFDubgitAESzyS6QH65ebd7KCs6njXEL1kh1iCweiodWT1xtq69VNx2Cwog97WEDt")
+ cy.get('#txt').type("\n[ccf2e5c3/48h/1h/0h/2h]Vpub5kon6Vda1Sx1xfPziprUxjBU9PjxGisfosRz3yvWz9odArUVF4embnoB4rEN76CVc5r1UB5JYXxzHTSQS6M1mAob8Wsw6FXk57RubBaizov")
+ }
+ cy.contains("Continue").click()
})
})
@@ -151,6 +149,40 @@ Cypress.Commands.add("addHotWallet", (wallet_name, device_name, node_type, walle
})
})
+Cypress.Commands.add("addWallet", (wallet_name, device_name, wallet_type, funded, node_type) => {
+ if (wallet_type == null) {
+ wallet_type = "segwit"
+ }
+ if (device_name == null) {
+ device_name = "DIY ghost"
+ }
+ cy.get('body').then(($body) => {
+ if ($body.text().includes(wallet_name)) {
+ cy.contains(wallet_name).click()
+ cy.get('#btn_settings' ).click( {force: true})
+ cy.get('#advanced_settings_tab_btn').click()
+ cy.get('#delete_wallet').click()
+ }
+ cy.get('#side-content').click()
+ cy.get('#btn_new_wallet').click()
+ cy.get('[href="./simple/"]').click()
+ var device_button = "#"+device_name.toLowerCase().replace(/ /g,"_")
+ cy.get(device_button).click()
+ cy.get('#wallet_name').type(wallet_name)
+ if (wallet_type == "nested_segwit") {
+ cy.get('#type_nested_segwit_btn').click()
+ }
+ if (wallet_type == "taproot") {
+ cy.get('#type_taproot_btn').click()
+ }
+ cy.get('#keysform > .centered').click()
+ cy.get('body').contains("New wallet was created successfully!")
+ cy.get('#btn_continue').click()
+ if (funded) {
+ cy.mine2wallet(node_type)
+ }
+ })
+})
Cypress.Commands.add("deleteWallet", (name) => {
cy.get('body').then(($body) => {
if ($body.text().includes(name)) {
diff --git a/cypress_basics.json b/cypress_basics.json
new file mode 100644
index 000000000..8701aafa0
--- /dev/null
+++ b/cypress_basics.json
@@ -0,0 +1,11 @@
+{
+ "testFiles": [
+ "spec_configures_nodes.js",
+ "spec_ghost_machine.js"
+ ],
+ "baseUrl": "http://localhost:25444",
+ "env": {
+ "broadcast_timeout":"8000"
+ },
+ "includeShadowDom": false
+}
diff --git a/src/cryptoadvance/specter/cli/cli_noded.py b/src/cryptoadvance/specter/cli/cli_noded.py
index db9600739..9ab8c182e 100644
--- a/src/cryptoadvance/specter/cli/cli_noded.py
+++ b/src/cryptoadvance/specter/cli/cli_noded.py
@@ -444,18 +444,18 @@ def miner_loop(node_impl, my_node, data_folder, mining_every_x_seconds, echo):
def mine_2_specter_wallets(node_impl, my_node, data_folder, echo):
- """Get each specter-wallet some coins"""
+ """Sending coins to all Specter wallets, except for "Fresh wallet" which is not supposed to have any tx"""
from ..process_controller.node_controller import fetch_wallet_addresses_for_mining
+ # Using the dict key, not the wallet name
+ exception = "fresh_wallet"
try:
-
- for address in fetch_wallet_addresses_for_mining(node_impl, data_folder):
- echo("")
+ for address in fetch_wallet_addresses_for_mining(
+ node_impl, data_folder, exception
+ ):
echo(f"Mining to address {address}")
my_node.testcoin_faucet(address)
- # my_node.mine(address=address)
- # my_node.mine(block_count=100)
except FileNotFoundError:
- # might happen if there no ~/.specter folder yet
+ # might happen if there is no ~/.specter folder yet
pass
diff --git a/src/cryptoadvance/specter/process_controller/node_controller.py b/src/cryptoadvance/specter/process_controller/node_controller.py
index 0261c25c9..6b86dc898 100644
--- a/src/cryptoadvance/specter/process_controller/node_controller.py
+++ b/src/cryptoadvance/specter/process_controller/node_controller.py
@@ -555,9 +555,10 @@ def find_node_executable(node_impl):
return which(f"{node_impl}d")
-def fetch_wallet_addresses_for_mining(node_impl, data_folder):
- """parses all the wallet-jsons in the folder (default ~/.specter/wallets/regtest)
- and returns an array with the addresses
+def fetch_wallet_addresses_for_mining(node_impl, data_folder, exception=None):
+ """
+ Parses all the wallet jsons in the folder (default ~/.specter/wallets/regtest) and returns an array with the addresses.
+ Pass a wallet name via the exception argument so that this wallet's addresses are not included.
"""
print(f"{data_folder}/wallets")
print(os.listdir(f"{data_folder}"))
@@ -569,6 +570,11 @@ def fetch_wallet_addresses_for_mining(node_impl, data_folder):
f"{data_folder}/{folder}/{'regtest' if node_impl == 'bitcoin' else 'elreg'}"
)
wallets = load_jsons(wallet_folder)
+ if exception and exception in wallets:
+ print(
+ f"Deleting wallet {exception} from wallets that receive faucet coins in testing."
+ )
+ del wallets[exception]
address_array = [value["address"] for key, value in wallets.items()]
# remove duplicates
address_array = list(dict.fromkeys(address_array))
diff --git a/src/cryptoadvance/specter/server_endpoints/wallets.py b/src/cryptoadvance/specter/server_endpoints/wallets.py
index 01ca7abf6..3c445fac4 100644
--- a/src/cryptoadvance/specter/server_endpoints/wallets.py
+++ b/src/cryptoadvance/specter/server_endpoints/wallets.py
@@ -828,6 +828,7 @@ def settings(wallet_alias):
else:
app.specter.wallet_manager.rename_wallet(wallet, wallet_name)
+ scroll_to_rescan_blockchain = request.args.get("rescan_blockchain")
return render_template(
"wallet/settings/wallet_settings.jinja",
purposes=purposes,
@@ -836,4 +837,5 @@ def settings(wallet_alias):
specter=app.specter,
rand=rand,
error=error,
+ scroll_to_rescan_blockchain=scroll_to_rescan_blockchain,
)
diff --git a/src/cryptoadvance/specter/static/styles.css b/src/cryptoadvance/specter/static/styles.css
index bb2826856..7277a3393 100644
--- a/src/cryptoadvance/specter/static/styles.css
+++ b/src/cryptoadvance/specter/static/styles.css
@@ -345,7 +345,7 @@ nav .separator{
background: var(--cmap-border);
border: 1px solid transparent;
border-radius: 4px;
- padding: 8px 15px 8px 10px;
+ padding: 8px 10px 8px 10px;
color: #fff;
font-size: 0.85em;
text-align: center;
@@ -742,7 +742,7 @@ th{
font-weight: inherit;
border-bottom: 3px solid var(--cmap-bg-lightest);
}
-tbody tr:hover{
+tbody tr:not(.nohover):hover{
background: rgba(255,255,255,0.03);
color: #fff;
}
@@ -832,12 +832,6 @@ table a:hover, .address-link:hover{
color: #fff;
text-decoration: underline;
}
-table .btn{
- margin: -10px 0;
- padding: 5px 10px;
- width: auto;
- min-width: 0;
-}
table .btn.hovering{
opacity: 0.2;
}
diff --git a/src/cryptoadvance/specter/templates/includes/addresses-table.html b/src/cryptoadvance/specter/templates/includes/addresses-table.html
index 0b67fb686..023da51dd 100644
--- a/src/cryptoadvance/specter/templates/includes/addresses-table.html
+++ b/src/cryptoadvance/specter/templates/includes/addresses-table.html
@@ -109,7 +109,7 @@
›
-