mirror of
https://github.com/cryptoadvance/specter-desktop.git
synced 2026-08-13 12:33:29 +02:00
Chore: Dynamic fee rate optimisations & Cypress tests (#1878)
* changes to fee-selection.html * cypress tests * accounting for low non-integer fees * renaming
This commit is contained in:
parent
f7b3b557b2
commit
c528e90b0d
8 changed files with 181 additions and 8 deletions
|
|
@ -6,6 +6,7 @@
|
|||
"spec_configures_nodes.js",
|
||||
"spec_devices.js",
|
||||
"spec_ghost_machine.js",
|
||||
"spec_fees.js",
|
||||
"spec_rescan.js",
|
||||
"spec_qr_signing.js",
|
||||
"spec_wallet_send.js",
|
||||
|
|
|
|||
1
cypress/fixtures/fees/asymmetric_fees.json
Normal file
1
cypress/fixtures/fees/asymmetric_fees.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"result": {"fastestFee": 13, "halfHourFee": 4, "hourFee": 2, "minimumFee": 1}, "error_messages": []}
|
||||
1
cypress/fixtures/fees/high_fees.json
Normal file
1
cypress/fixtures/fees/high_fees.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"result": {"fastestFee": 14, "halfHourFee": 10, "hourFee": 7, "minimumFee": 1}, "error_messages": []}
|
||||
1
cypress/fixtures/fees/low_fees.json
Normal file
1
cypress/fixtures/fees/low_fees.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"result": {"fastestFee": 1, "halfHourFee": 1, "hourFee": 1, "minimumFee": 1}, "error_messages": []}
|
||||
1
cypress/fixtures/fees/low_non-integer_fees.json
Normal file
1
cypress/fixtures/fees/low_non-integer_fees.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"result": {"fastestFee": 1.1, "halfHourFee": 1, "hourFee": 1, "minimumFee": 1}, "error_messages": []}
|
||||
1
cypress/fixtures/fees/normal_fees.json
Normal file
1
cypress/fixtures/fees/normal_fees.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"result": {"fastestFee": 9, "halfHourFee": 5, "hourFee": 3, "minimumFee": 1}, "error_messages": []}
|
||||
157
cypress/integration/spec_fees.js
Normal file
157
cypress/integration/spec_fees.js
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// This spec file assumes that the Ghost wallet is available,
|
||||
// Fetch API values for fees are mocked
|
||||
|
||||
describe('Test the fee UI', () => {
|
||||
before(() => {
|
||||
Cypress.config('includeShadowDom', true)
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
// Keeps the session cookie alive, Cypress by default clears all cookies before each test
|
||||
beforeEach(() => {
|
||||
cy.viewport(1200,660)
|
||||
Cypress.Cookies.preserveOnce('session')
|
||||
})
|
||||
|
||||
it('Using dynamic mode with normal fees', () => {
|
||||
// Fees: {"fastestFee": 9, "halfHourFee": 5, "hourFee": 3, "minimumFee": 1}
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/normal_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
// Preselected dynamic fee rate
|
||||
cy.get('#fee_rate_dynamic_text').should('have.text', '5')
|
||||
// Speed text
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Fast (30 minutes)')
|
||||
// Slider
|
||||
cy.get('#fees_slider').should('have.value', '5')
|
||||
cy.get('#fees_slider').invoke('attr', 'min').should('eq', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'max').should('eq', '12')
|
||||
// Simulate sliding to 1.5
|
||||
cy.get('#fees_slider').invoke('val', '1.5').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '1.5')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Very slow')
|
||||
// Sliding to 2
|
||||
cy.get('#fees_slider').invoke('val', '2').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '2')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Slow')
|
||||
// Sliding to 11
|
||||
cy.get('#fees_slider').invoke('val', '11').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '11')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Overpaid! (10 minutes)')
|
||||
})
|
||||
|
||||
it('Using dynamic mode with low fees', () => {
|
||||
// Fees: {"fastestFee": 1, "halfHourFee": 1, "hourFee": 1, "minimumFee": 1}
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/low_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
// Preselected dynamic fee rate
|
||||
cy.get('#fee_rate_dynamic_text').should('have.text', '1')
|
||||
// Speed text
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Very fast (10 minutes)')
|
||||
// Slider
|
||||
cy.get('#fees_slider').should('have.value', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'min').should('eq', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'max').should('eq', '1.5')
|
||||
// Simulate sliding to 1.5
|
||||
cy.get('#fees_slider').invoke('val', '1.5').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '1.5')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Overpaid! (10 minutes)')
|
||||
})
|
||||
|
||||
it('Using dynamic mode with low non-integer fees', () => {
|
||||
// Fees: {"fastestFee": 1.1, "halfHourFee": 1, "hourFee": 1, "minimumFee": 1}
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/low_non-integer_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
// Preselected dynamic fee rate
|
||||
cy.get('#fee_rate_dynamic_text').should('have.text', '1')
|
||||
// Speed text
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Fast (30 minutes)')
|
||||
// Slider
|
||||
cy.get('#fees_slider').should('have.value', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'min').should('eq', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'max').should('eq', '2')
|
||||
// Simulate sliding to 1.1
|
||||
cy.get('#fees_slider').invoke('val', '1.1').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '1.1')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Very fast (10 minutes)')
|
||||
})
|
||||
|
||||
it('Using dynamic mode with high fees', () => {
|
||||
// Fees: {"fastestFee": 14, "halfHourFee": 10, "hourFee": 7, "minimumFee": 1}
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/high_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
// Preselected dynamic fee rate
|
||||
cy.get('#fee_rate_dynamic_text').should('have.text', '7')
|
||||
// Speed text
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Medium (1 hour)')
|
||||
// Slider
|
||||
cy.get('#fees_slider').should('have.value', '7')
|
||||
cy.get('#fees_slider').invoke('attr', 'min').should('eq', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'max').should('eq', '19')
|
||||
// Simulate sliding to 3
|
||||
cy.get('#fees_slider').invoke('val', '3').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '3')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Very slow')
|
||||
// Simulate sliding to 4.5
|
||||
cy.get('#fees_slider').invoke('val', '4.5').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '4.5')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Slow')
|
||||
})
|
||||
|
||||
it('Using dynamic mode with asymmetric fees', () => {
|
||||
// Fees: {"fastestFee": 13, "halfHourFee": 4, "hourFee": 2, "minimumFee": 1}
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/asymmetric_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
// Preselected dynamic fee rate
|
||||
cy.get('#fee_rate_dynamic_text').should('have.text', '2')
|
||||
// Speed text
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Medium (1 hour)')
|
||||
// Slider
|
||||
cy.get('#fees_slider').should('have.value', '2')
|
||||
cy.get('#fees_slider').invoke('attr', 'min').should('eq', '1')
|
||||
cy.get('#fees_slider').invoke('attr', 'max').should('eq', '18')
|
||||
// Simulate sliding to 12.5
|
||||
cy.get('#fees_slider').invoke('val', '12.5').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '12.5')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Fast (30 minutes)')
|
||||
// Simulate sliding to 4
|
||||
cy.get('#fees_slider').invoke('val', '4').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '4')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Fast (30 minutes)')
|
||||
// Simulate sliding to 3
|
||||
cy.get('#fees_slider').invoke('val', '3').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '3')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Medium (1 hour)')
|
||||
// Simulate sliding to 1.6
|
||||
cy.get('#fees_slider').invoke('val', '1.6').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '1.6')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Slow')
|
||||
// Simulate sliding to 1.2
|
||||
cy.get('#fees_slider').invoke('val', '1.2').trigger('input')
|
||||
cy.get('#fees_slider').should('have.value', '1.2')
|
||||
cy.get('#fee_rate_speed_text').should('have.text', 'Very slow')
|
||||
})
|
||||
|
||||
it('Using manual mode', () => {
|
||||
cy.selectWallet('Ghost wallet')
|
||||
cy.intercept('GET', '/wallets/fees', { fixture: 'fees/normal_fees.json' })
|
||||
cy.get('#btn_send').click()
|
||||
cy.get('#toggle_advanced').click()
|
||||
cy.get('.fee_container').find('#fee_option_manual').click()
|
||||
cy.get('#fee_manual').find('#fee_rate').should('have.value', '1')
|
||||
cy.get('#fee_manual').find('#fee_rate').clear( { force: true })
|
||||
cy.get('#fee_manual').find('#fee_rate').type(5, { force: true })
|
||||
cy.get('#fee_manual').find('#fee_rate').should('have.value', '5')
|
||||
cy.get('#fee_manual').find('.note').contains('1 sat/vbyte is the minimal fee rate.')
|
||||
})
|
||||
|
||||
})
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
</div>
|
||||
<div id ="fee_dynamic" style="display: {% if fee_options_dynamic %}block{% else %}none{% endif %}">
|
||||
<div id="blocks"></div>
|
||||
<input type="range" style="width: 12em" min="{{min_fee}}" max="" value="" step="1" id="fees_slider">
|
||||
<input type="range" style="width: 12em" min="{{min_fee}}" max="" value="" step="0.1" id="fees_slider">
|
||||
<input type="hidden" id="fee_rate_dynamic" name="fee_rate_dynamic" value="{{min_fee}}">
|
||||
<div>
|
||||
{{ _("Estimated speed:") }} <span id="fee_rate_speed_text"></span>
|
||||
|
|
@ -238,11 +238,21 @@
|
|||
// Gets executed after fee initialisation
|
||||
initWithFees() {
|
||||
// this.feesSlider.min is set above via min_fee
|
||||
this.feesSlider.max = Math.floor(this.fees["fastestFee"] * 1.4)
|
||||
let sliderMin = this.fees["minimumFee"]
|
||||
let sliderMax = this.fees["fastestFee"]
|
||||
let average = Math.floor((sliderMin + sliderMax) / 2)
|
||||
this.feesSlider.value = average
|
||||
// For low fee environment, API results are integers
|
||||
if (this.fees["fastestFee"] == 1) {
|
||||
this.feesSlider.max = 1.5
|
||||
}
|
||||
else {
|
||||
let feeSliderMax = Math.floor(this.fees["fastestFee"] * 1.4)
|
||||
this.feesSlider.max = feeSliderMax >= 2 ? feeSliderMax : 2
|
||||
}
|
||||
// Avoid calculating the default value with a very high fastestFee
|
||||
if (this.fees["fastestFee"] > 2 * this.fees["halfHourFee"]) {
|
||||
this.feesSlider.value = Math.floor((this.fees["minimumFee"] + this.fees["hourFee"] + this.fees["halfHourFee"]) / 3)
|
||||
}
|
||||
else {
|
||||
this.feesSlider.value = Math.floor((this.fees["minimumFee"] + this.fees["fastestFee"]) / 2)
|
||||
}
|
||||
this.dynamicFeeUpdated() // otherwise no text next to estimated speed
|
||||
}
|
||||
|
||||
|
|
@ -274,9 +284,9 @@
|
|||
let hourFee = this.fees["hourFee"]
|
||||
let halfHourFee = this.fees["halfHourFee"]
|
||||
let fastestFee = this.fees["fastestFee"]
|
||||
if (this.feesSlider.value <= minFee + ((hourFee - minFee) / 2)) {
|
||||
if (this.feesSlider.value < minFee + ((hourFee - minFee) / 2)) {
|
||||
this.fee_rate_speed_text.innerText = '{{ _("Very slow") }}';
|
||||
} else if (this.feesSlider.value > minFee + ((hourFee - minFee) / 2) && this.feesSlider.value < hourFee) {
|
||||
} else if (this.feesSlider.value >= minFee + ((hourFee - minFee) / 2) && this.feesSlider.value < hourFee) {
|
||||
this.fee_rate_speed_text.innerText = '{{ _("Slow") }}';
|
||||
} else if (this.feesSlider.value >= hourFee && this.feesSlider.value < halfHourFee) {
|
||||
this.fee_rate_speed_text.innerText = '{{ _("Medium (1 hour)") }}';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue