Skip to content

Commit

Permalink
Merge branch 'master' into refactor_wallet_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
k9ert authored Jun 19, 2022
2 parents 68027fc + 14cb11b commit b0f112d
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 40 deletions.
43 changes: 23 additions & 20 deletions cypress/integration/spec_plugins.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
describe('plugins are working', () => {

it('can create the associate button', () => {
describe('Test plugins', () => {
before(() => {
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('/')

})

it('Associate an address with a service', () => {
// choose address
cy.get('#test_hot_wallet_1-sidebar-list-item').click()
cy.get('[href="/wallets/wallet/test_hot_wallet_1/addresses/"]').click()
cy.get('addresses-table').shadow().find('address-row').eq(0).shadow().find('.explorer-link').eq(0).click({position: 'top'})
cy.get('address-data').shadow().find('#associate-btn').click()

cy.selectWallet("Wallet ghost")
cy.get('main').contains('Addresses').click()
// Click on the first address
cy.contains('td', '#0').siblings().contains('bcrt').click()
cy.get('#associate-btn').click()
cy.contains("Service integration requires an authentication method that includes a password")
// ok, let's set a password
// OK, let's set a password
cy.get('select').select("passwordonly")
cy.get('#specter_password_only').type("mySecretPassword")
cy.get('#submit-btn').click()
cy.contains("Admin password successfully updated")

// choose address again
cy.get('#test_hot_wallet_1-sidebar-list-item').click()
cy.get('[href="/wallets/wallet/test_hot_wallet_1/addresses/"]').click()
cy.get('addresses-table').shadow().find('address-row').eq(0).shadow().find('.explorer-link').eq(0).click()
cy.get('address-data').shadow().find('#associate-btn').click()
// Choose address again
cy.selectWallet("Wallet ghost")
cy.get('main').contains('Addresses').click()
cy.contains('td', '#0').siblings().contains('bcrt').click()
cy.get('#associate-btn').click()
cy.contains("Associating an address with a service will")


})

it('deactivates the password protection again', () => {
cy.viewport(1200,660)
cy.visit('/')
it('Deactivate password protection', () => {
// This flow only works if we don't keep the session alive! So, no Cypress.Cookies.preserveOnce('session') in beforeEach().
cy.get('#password').type("mySecretPassword")
cy.get('#login-btn').click()
cy.get('[href="/settings/"] > .svg-white').click()
Expand Down
73 changes: 68 additions & 5 deletions cypress/integration/spec_wallet_send.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
describe('Send transactions from bitcoin hotwallets', () => {
it('Creates a single sig bitcoin hotwallet on specter and send transaction', () => {
describe('Test sending transactions', () => {
before(() => {
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('Send a standard transaction', () => {
// empty so far
cy.addHotDevice("Hot Device 1","bitcoin")
cy.get('body').then(($body) => {
Expand Down Expand Up @@ -42,9 +51,60 @@ describe('Send transactions from bitcoin hotwallets', () => {
})
})

it('Creates a multi sig wallet on specter and send transaction', () => {
cy.viewport(1200,660)
cy.visit('/')
it('Create a transaction with multiple recipients', () => {
// We need new sats but mine2wallet only works if a wallet is selected
cy.selectWallet("Test Hot Wallet 1")
cy.mine2wallet("btc")
cy.get('#btn_send').click()
/// The addresses are the first three from DIY ghost
cy.get('#address_0').type("bcrt1qvtdx75y4554ngrq6aff3xdqnvjhmct5wck95qs")
cy.get('#label_0').type("Recipient 1")
cy.get('#amount_0').type(10)
cy.get('#toggle_advanced').click()
cy.get('main').scrollTo('bottom')
cy.get('#add-recipient').click()
cy.get('#address_1').type("bcrt1qgzmq6e3tn67kveryf2je6nd3nv4txef4sl8wre")
cy.get('#label_1').type("Recipient 2")
cy.get('#amount_1').type(5)
cy.get('main').scrollTo('bottom')
cy.get('#add-recipient').click()
cy.get('#address_2').type("bcrt1q9mkrhmxcn7rslzfv6lke8859m7ntwudfjqmcx7")
cy.get('#label_2').type("Recipient 3")
cy.get('#send_max_2').click()
cy.get('main').scrollTo('bottom')
// Shadow DOM
// Check whether the subtract fees box is ticked
cy.get('#fee-selection-component').find('.fee_container').find('input#subtract').invoke('prop', 'checked').should('eq', true)
// Check whether the recipient number input field is visible (shadow DOM)
cy.get('#fee-selection-component').find('.fee_container').find('span#subtract_from').should('be.visible')
// Light DOM
// Check the values of the hidden inputs in the light DOM which are used for the form
// Note: Despite identical ids the hidden inputs seem to be fetched first since they are higher up in the DOM
cy.get('#fee-selection-component').find('#subtract').invoke('attr', 'value').should('eq', 'true')
// Send max was applied to the third recipient, so the value should be 3
cy.get('#fee-selection-component').find('#subtract_from_input').invoke('attr', 'value').should('eq', '3')

// Change recipient number to 2
// Note: No easy way to increment / decrement by clicking, see: https://stackoverflow.com/questions/47180137/incrementing-and-decrementing-the-value-of-an-input-type-number-in-cypress
cy.get('#fee-selection-component').find('.fee_container').find('#subtract_from_input').clear()
cy.get('#fee-selection-component').find('.fee_container').find('#subtract_from_input').click().type('2{enter}')
cy.get('#fee-selection-component').find('#subtract_from_input').invoke('attr', 'value').should('eq', '2')

// Change it back to recipient 3
cy.get('#send_max_2').click()

// The fee should be subtracted from the third recipient
cy.get('#create_psbt_btn').click()
cy.get('div.tx_info > :nth-child(3) > :nth-child(1)').then(($div) => {
const amount = parseFloat($div.text())
expect(amount).to.be.lte(5)
})
cy.get('#deletepsbt_btn').click()
// Clean up (Hot Device 1 is still needed below)
cy.deleteWallet("Test Hot Wallet 1")
})

it('Send a transaction from a multisig wallet', () => {
cy.get('body').then(($body) => {
if ($body.text().includes('Test Multisig Wallet 1')) {
cy.get('#wallets_list > .item > svg').click()
Expand Down Expand Up @@ -83,5 +143,8 @@ describe('Send transactions from bitcoin hotwallets', () => {
const n = parseFloat($div.text())
expect(n).to.be.equals(0)
})
// Clean up
cy.deleteWallet("Test Multisig Wallet 1")
cy.deleteDevice("Hot Device 1")
})
})
1 change: 0 additions & 1 deletion cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ module.exports = (on, config) => {
}
})

// For future use, not used yet
on('task', {
'delete:bitcoin-hotwallet': (name) => {
console.log('connection details: %s', btc_conn)
Expand Down
12 changes: 12 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ Cypress.Commands.add("deleteDevice", (name) => {
cy.contains(name).click()
cy.get('#forget_device').click()
cy.reload()
// For hot wallets only
cy.task("delete:bitcoin-hotwallet")
cy.task("delete:elements-hotwallet")
}
})
})
Expand Down Expand Up @@ -162,8 +165,17 @@ Cypress.Commands.add("deleteWallet", (name) => {
})
})

Cypress.Commands.add("selectWallet", (name) => {
cy.get('body').then(($body) => {
if ($body.text().includes(name)) {
cy.contains(name).click()
}
})
})

Cypress.Commands.add("mine2wallet", (chain) => {
// Fund it and check the balance
// Only works if a wallet is selected, use addHotWallet / selectWallet commands before if needed
cy.get('#btn_transactions').click()
cy.get('#fullbalance_amount', { timeout: Cypress.env("broadcast_timeout") }).then(($span) => {
const oldBalance = parseFloat($span.text())
Expand Down
6 changes: 3 additions & 3 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ it each time it's starting with the genesis-block. This has some implications:
* Depending on whether you do one or the other, you cannot rely on transactionIDs. So if you run a test standalone twice, you can assert txids but you can't any longer when you run all the tests

### Cypress UI-testing
Cypress is just awesome. It's quite easy to create Frontend-tests and it's even recording all tests and you can immediately see how it went. So each test-run, the tests are kept for one day (see the ["artifacts-section"](https://github.com/k9ert/specter-desktop/blob/cypress/.gitlab-ci.yml#L53-L58)) and you can watch them by browsing the artifacts on any gitlab-job-page (right-hand-side marked with "Job artifacts").
Cypress is just awesome. It's quite easy to create Frontend-tests and it's even recording all tests and you can immediately see how it went. So each test-run, the tests are kept for one day (see the ["artifacts-section"](https://github.com/cryptoadvance/specter-desktop/blob/master/.gitlab-ci.yml) and you can watch them by browsing the artifacts on any gitlab-job-page (right-hand-side marked with "Job artifacts").

Executing the tests is done via `./utils/test-cypress.sh`:
```
Expand All @@ -237,7 +237,7 @@ Executing the tests is done via `./utils/test-cypress.sh`:
```
The test_specifications which get executed are specified in `cypress.json`.

More details on cypress-testing can be found in [cypress-testing.md](docs/cypress-testing.md).
More details on cypress-testing can be found in [cypress-testing.md](./cypress-testing.md).
Make sure to read it. The tooling we created around cypress might be quite helpful in daily development.
In short, you can do this and the last command will give you a reliable development-environment which is the very same whenever you start it anew:
```
Expand All @@ -254,7 +254,7 @@ Other than Django, Flask is not opionoated at all. You can do all sorts of thing
One strange thing which we're doing to get the tests working is forcing the reload of the controller-code (if necessary) [here](https://github.com/cryptoadvance/specter-desktop/blob/master/src/cryptoadvance/specter/server.py#L88-L93).

The if-clause might be quite brittle which would result in very strange 404 in test_controller.
Check the [archblog](./docs/archblog.md) for a better explanation.
Check the [archblog](./archblog.md) for a better explanation.
If Someone could figure out a better way to do that avoiding this strange this ... very welcome.

## More on the bitcoind requirements
Expand Down
8 changes: 8 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v1.10.2 Juni 03, 2022
- Feature: Basic auth in electron #1730 (djpnewton)
- Feature: Multisig beginner guide #1731 (relativisticelectron)
- Bugfix: Corrected build instructions and made virtuelenv name dynamic #1735 (relativisticelectron)
- Bugfix: issues while using specter as library #1740 (k9ert)
- Bugfix: PDF backup does not open for multisig #1741 (k9ert)
- UIUX: fix typo in error_logs #1739 (Bufo)

## v1.10.0 Mai 27, 2022
- Feature: adding has_service() method to user #1732 (Kim Neunert)
- Feature: Choose file button for labels import #1682 (Manolis)
Expand Down
1 change: 0 additions & 1 deletion src/cryptoadvance/specter/static/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,6 @@ nav.side > a.item.active, nav.side > div > a.item.active{
max-width: 90%;
padding-left: 1em;
padding-right: 1em;
padding-top: .5em;
margin-bottom: 1em;
background-color: #263044;
border: 1px solid #CCCCCC;
Expand Down
12 changes: 6 additions & 6 deletions src/cryptoadvance/specter/templates/base.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@
{% endif %}
<div style="display: flex; justify-content: center; align-items: center;">
<div class="main-description-box">
<p style="font-size: 1.1em; margin-bottom: 2em; text-align: left;">{{ _("Specter Desktop is a convenient wallet interface to better use your Bitcoin Core node. It’s good for singlesig wallets, but comes with a special focus on multisignature setups for different hardware wallets and air-gapped signing devices.") }}
Learn <a style="color: #fff" href="https://specter-desktop-docs.netlify.app/multisig-guide/" target="_blank">🕮 {{ _("here") }}</a> more about multisig.
<p style="font-size: 1.1em; margin: 1em auto 1em auto; text-align: left;">{{ _("Specter Desktop is a convenient wallet interface to better use your Bitcoin Core node. It’s good for singlesig wallets, but comes with a special focus on multisignature setups for different hardware wallets and air-gapped signing devices.") }} <br><br>
&#128217; Learn <a style="color: #fff" href="https://specter-desktop-docs.netlify.app/multisig-guide/" target="_blank">{{ _("here") }}</a> more about multisig.
</p>
</div>
</div>
Expand Down Expand Up @@ -243,14 +243,14 @@
</table>
<br>
{% endif %}
<p style="position: relative; z-index: 1; line-height: 24px;">{{ _('Have a look at our <a href="https://specter-desktop-docs.netlify.app/" target="_blank" style="color: #fff; font-size: 1.05em; font-weight: bolder;">🕮 help</a> or <a href="https://specter-desktop-docs.netlify.app/faq/" target="_blank" style="color: #fff; font-size: 1.05em; font-weight: bolder;">FAQ</a>') }}</p><br><br>
<span style="position: relative; z-index: 1;">{{ _("Still having issues?") }}</span><br>
<p style="position: relative; z-index: 1; line-height: 24px; font-size: 1.1em">&#128064;{{ _(' Have a look at our <a href="https://specter-desktop-docs.netlify.app/" target="_blank" style="color: #fff; font-weight: bolder;">documentation</a> and the <a href="https://specter-desktop-docs.netlify.app/faq/" target="_blank" style="color: #fff; font-weight: bolder;">FAQ</a>') }}</p><br>
<span style="position: relative; z-index: 1;">&#128583;{{ _(" Still having issues?") }}</span><br>
<div style="display: flex; justify-content: center;">
<div style="max-width: 80%;">
<p style="position: relative; z-index: 1;">{{ _('Feel free to <a href="https://github.com/cryptoadvance/specter-desktop/issues/new" target="_blank" style="color: #fff;">open an issue on the GitHub</a> or ask in the <a href="https://t.me/spectersupport" target="_blank" style="color: #fff;">Specter Community telegram chat</a>') }}</p>
<p style="position: relative; z-index: 1;">{{ _('Feel free to <a href="https://github.com/cryptoadvance/specter-desktop/issues/new" target="_blank" style="color: #fff;">open an issue on GitHub</a> or ask in the <a href="https://t.me/spectersupport" target="_blank" style="color: #fff;">Specter Community telegram chat</a>') }}</p>
</div>
</div>
<br><br>
<br>
<a href="https://github.com/cryptoadvance/specter-desktop#help-wanted-do-you-like-specter" target="_blank" style="position: relative; z-index: 1; color: #fff; display: inline-block;"><h2 id="help-wanted-text" style="display: inline-block;">{{ _('Help wanted: Do you like Specter?') }}</h2><img src="{{ url_for('static', filename='img/love.png') }}" width="20px" style="vertical-align: sub; margin-left: 10px;"/></a>
<div class="footer">
<span style="position: relative; z-index: 1;">{{ _("Supported and maintained by") }}:</span><br>
Expand Down
10 changes: 8 additions & 2 deletions src/cryptoadvance/specter/templates/includes/fee-selection.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</div>
<span id="subtract_from" style="display: none">
<br>{{ _("Subtract from recipient number:") }}
<input id="subtract_from_input" name="subtract_from" type="number" min="1" value="1" step="1" style="width: 80px; min-width: 80px;"><br>
<input id="subtract_from_input" name="subtract_from_stale" type="number" min="1" value="1" step="1" style="width: 80px; min-width: 80px;"><br>
</span>
<br>
<div>
Expand Down Expand Up @@ -175,6 +175,7 @@
// subtract_from (the actual input field)
this.ld.subtractFromInput = this.subtractFromInput.cloneNode(true);
this.ld.subtractFromInput.type = "hidden";
this.ld.subtractFromInput.name = "subtract_from";
this.appendChild(this.ld.subtractFromInput);

// This is just for exposure to the jinja template for displaying, not needed for the form POST
Expand Down Expand Up @@ -208,7 +209,7 @@
this.rbfUpdated();
})

this.subtractFromInput.addEventListener("click", (event) => {
this.subtractFromInput.addEventListener("change", (event) => {
this.subtractUpdated();
})

Expand Down Expand Up @@ -332,6 +333,11 @@
} catch(e) {console.log(e)}
}


setSubtractFrom(recipient) {
this.subtractFromInput.value = recipient
}

// Updates Light DOM values for the form
subtractUpdated() {
if (this.subtract.checked) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
{% include "wallet/new_wallet/components/import_wallet_account_map.jinja" %}


<span style="font-size: 1.2em; margin: 10px; text-align: center;">
New to Multisig? Read our <a style="color: #fff" href="https://specter-desktop-docs.netlify.app/multisig-guide/" target="_blank">🕮 {{ _("Multisig guide") }}</a>
<span style="font-size: 1.1em; margin: 10px; text-align: center;">
{{ _("New to multisig? ") }}&#128217;{{ _(" Learn") }} <a style="color: #fff" href="https://specter-desktop-docs.netlify.app/multisig-guide/" target="_blank">here</a> {{ _("more about multisig") }}.
</span>
<br>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@
}
async function setMaxAmount(i) {
FeeSelectionComponent.showSubtractFrom(true)
FeeSelectionComponent.setSubtractFrom(i + 1)
let amountInput = document.getElementById('amount_' + i);
if (!validAddress(i)) {
return;
Expand Down
23 changes: 23 additions & 0 deletions utils/test-all-linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash


pip3 install virtualenv
virtualenv --python=python3 .env
source .env/bin/activate
pip3 install -r requirements.txt --require-hashes
pip3 install -e .
python3 setup.py install # also compiles the babel translation-files


pip3 install -r test_requirements.txt
./tests/install_noded.sh --bitcoin binary
./tests/install_noded.sh --elements binary


export PATH=./tests/elements/bin/:./tests/bitcoin/bin/:$PATH

rm -Rf ./cypress/videos ./cypress/screenshots

./utils/test-cypress.sh run
pytest

0 comments on commit b0f112d

Please sign in to comment.