status-desktop/storybook/qmlTests/TestComponents/tst_DerivationPathInput.qml

186 lines
11 KiB
QML
Raw Normal View History

feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQml 2.14
import QtTest 1.0
import StatusQ 0.1 // https://github.com/status-im/status-desktop/issues/10218
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
import AppLayouts.Wallet.addaccount.panels 1.0
import AppLayouts.Wallet.addaccount.panels.DerivationPathInput 1.0
Item {
id: root
width: 600
height: 400
TestCase {
name: "DerivationPathInputControllerTests"
Component {
id: controllerComponent
Controller {
enabledColor: "white"
frozenColor: "black"
errorColor: "red"
warningColor: "orange"
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
}
}
property Controller controller: null
function init() {
controller = createTemporaryObject(controllerComponent, root)
}
function test_parseRegularBases_data() {
return [
{tag: "Ethereum Standard", base: "m/44'/60'/0'/0", expected: ["m/44'/", "60", "'/", "0", "'/", "0"]},
{tag: "Custom", base: "m/44'", expected: ["m/44'"]},
{tag: "Custom with separator", base: "m/44'/", expected: ["m/44'/"]},
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
{tag: "Ethereum Ledger", base: "m/44'/60'/0'", expected: ["m/44'/", "60", "'/", "0", "'"]},
{tag: "Ethereum Ledger Live", base: "m/44'/60'", expected: ["m/44'/", "60", "'"]},
]
}
function test_parseRegularBases(data) {
let res = controller.parseDerivationPath(data.base)
compare(res.length, data.expected.length, `expect same length: ${JSON.stringify(res)} vs ${JSON.stringify(data.expected)}`)
for (const i in res) {
compare(data.expected[i], res[i].content)
}
}
function test_parseRegularDerivationPath_data() {
return [
{tag: "Ethereum one address index", derivationPath: "m/44'/60'/0'/0/1", expected: ["m/44'/", "60", "'/", "0", "'/", "0", "/", "1"]},
{tag: "Ethereum two address index", derivationPath: "m/44'/60'/0'/0/1/2", expected: ["m/44'/", "60", "'/", "0", "'/", "0", "/", "1", "/", "2"]},
{tag: "Ethereum Ledger", derivationPath: "m/44'/60'/0'/1/2", expected: ["m/44'/", "60", "'/", "0", "'/", "1", "/", "2"]},
{tag: "Ethereum Ledger Live", derivationPath: "m/44'/60'/1'/2/3", expected: ["m/44'/", "60", "'/", "1", "'/", "2", "/", "3"]},
{tag: "Empty entries", derivationPath: "m/44'/'/'//", expected: ["m/44'/", "", "'/", "", "'/", "", "/", ""]},
{tag: "Wrong entries", derivationPath: "m/44'/T<'/.?'/;/wrong", expected: ["m/44'/", "T<", "'/", ".?", "'/", ";", "/", "wrong"]},
{tag: "Custom corner-case coin only", derivationPath: "m/44'/77", expected: ["m/44'/", "77"]},
{tag: "Custom corner-case hardened coin only", derivationPath: "m/44'/12'", expected: ["m/44'/", "12", "'"]},
{tag: "Custom corner-case coin and separator", derivationPath: "m/44'/12'/", expected: ["m/44'/", "12", "'/", ""]},
{tag: "Custom corner-case coin and address", derivationPath: "m/44'/12'/03", expected: ["m/44'/", "12", "'/", "03"]},
{tag: "Custom corner-case coin and hardened address", derivationPath: "m/44'/12'/03'", expected: ["m/44'/", "12", "'/", "03", "'"]},
{tag: "Custom corner-case coin, address and separator", derivationPath: "m/44'/12'/03'/", expected: ["m/44'/", "12", "'/", "03", "'/", ""]},
{tag: "Custom corner-case coin, address and change", derivationPath: "m/44'/12'/03'/83", expected: ["m/44'/", "12", "'/", "03", "'/", "83"]},
{tag: "Custom corner-case coin, address, change and separator", derivationPath: "m/44'/12'/03'/83/", expected: ["m/44'/", "12", "'/", "03", "'/", "83", "/", ""]},
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
]
}
function test_parseRegularDerivationPath(data) {
let res = controller.parseDerivationPath(data.derivationPath)
compare(res.length, data.expected.length, `expect same element count for: ${JSON.stringify(res)} vs ${JSON.stringify(data.expected)}`)
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
for (const i in res) {
compare(data.expected[i], res[i].content, `expect same element for [${i}]: ${JSON.stringify(res)} vs ${JSON.stringify(data.expected)}`)
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
}
}
function test_completeDerivationPath_data() {
return [
{tag: "Ethereum", base: "m/44'/60'/0'/0", derivationPath: "m/44'/60'/0'/0/1", expected: ["m/44'/", "60", "'/", "0", "'/", "0", "/", "1"]},
{tag: "Ending in separator", base: "m/44'/60'/0'/0", derivationPath: "m/44'/60'/0'/0/", expected: ["m/44'/", "60", "'/", "0", "'/", "0", "/", ""]},
{tag: "Custom", base: "m/44'", derivationPath: "m/44'", expected: ["m/44'/", ""]},
{tag: "Ethereum Ledger", base: "m/44'", derivationPath: "m/44'/60'/0/1/2", expected: ["m/44'/", "60", "'/", "0", "'/", "1", "/", "2"]},
{tag: "Broken Ethereum", base: "m/44'", derivationPath: "m/44'/60/0'/0/1/2", expected: ["m/44'/", "60/0", "'/", "0", "/", "1", "/", "2"]},
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
]
}
function test_completeDerivationPath(data) {
let res = controller.completeDerivationPath(data.base, data.derivationPath)
verify(res.errorMessage.length === 0, `expect no error message, got "${res.errorMessage}"`)
compare(res.elements.length, data.expected.length, `expect same length for test data entry ${data.name}, ${JSON.stringify(res.elements)} vs ${JSON.stringify(data.expected)}`)
for (const i in res) {
compare(data.expected[i], res[i].content)
}
}
function test_parseRegularWrongDerivationPath_data() {
return [
{tag: "Other standard", derivationPath: "m/46'/60'/0'/0/1"},
{tag: "Incomplete", derivationPath: "m/44"},
{tag: "Ethereum", derivationPath: "'/46'/60'/0'/0/1"},
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
]
}
function test_parseRegularWrongDerivationPath(data) {
let res = controller.parseDerivationPath(data.derivationPath)
compare(res, null)
}
function test_validateAllElements_data() {
return [
{tag: "No error", derivationPath: "m/44'/60'/0'/0/1", error: "", warning: ""},
{tag: "No error regression", derivationPath: "m/44'/", error: "", warning: ""},
{tag: "Non-ethereum", derivationPath: "m/44'/83'/0'/0/1", error: "", warning: "Non-Ethereum cointype"},
{tag: "Numbers only", derivationPath: "m/44'/8d3'/0'/0/1", error: "Please enter numbers only", warning: ""},
{tag: "First address index too big", derivationPath: "m/44'/83'/0'/0/101", error: "Account number must be <100", warning: ""},
{tag: "Last address index too big", derivationPath: "m/44'/83'/0'/0/1/2/123", error: "Account number must be <100", warning: ""},
]
}
function test_validateAllElements(data) {
const res = controller.completeDerivationPath("m/44'", data.derivationPath)
var validationResult = controller.validateAllElements(res.elements)
var expectAllOk = true
if(data.error) {
verify(validationResult.error, `expect error message, got "${validationResult.error}"`)
expectAllOk = false
}
if(data.warning) {
verify(validationResult.warning, `expect warning message, got "${validationResult.warning}"`)
expectAllOk = false
}
if(expectAllOk) {
verify(!validationResult.error, `expect no error message, got "${validationResult.error}"`)
verify(!validationResult.warning, `expect no warning message, got "${validationResult.warning}"`)
}
}
feat(wallet): implement DerivationPathInput control The enforcing of the derivation path editing rules is done in a structured way by handling all the changes on the array of `Element` stored in d.elements and then recomposing the HTML string to be displayed after every change. Main limitation is the workaround in `onTextChanged` that regenerates the text in order to dismiss foreign characters introduced by pasting which I couldn't find a way to disable without disabling also the ability to copy content to clipboard. Highlights: - Implement DerivationPathInput control that intercepts the modifiable keyboard events in order to edit the visible TextEdit.text while respecting the requirements of the derivation path editing - Implement a JS Controller that handles the logic of the decomposing and recomposing the derivation path string - Add anew StatusQ with the TextEdit basic look and feel to be used in DerivationPathInput control without duplicating the style - Allow passing modifiable events that are not generating characters in order to allow copy to clipboard - Disable add account when control is in error state - Limit to maximum 5 elements in the derivation path Testing: - Integrate the control with StoryBook for a quick preview of the control - Add unit tests for the Controller basic functionality and regression for the main control Item - Removed forcing x64 architecture on apple arm64 hardware from the storybook build configuration Note: initially the implementation was suppose to be simple parse the derivation path string edit elements and format it. However, I could not find a quick way fix the circular dependency issue between editing the text and reformatting it. The solution was to use a one way from the structured data to the formatted string which complicates the implementation logic. Closes: #9890
2023-03-15 22:34:48 +00:00
Component {
id: testDataElementsComponent
Item {
Element { id: base; content: "m/44'/"; startIndex: 0; endIndex: 7; contentType: Element.ContentType.Base }
Element { id: coin; content: "60"; startIndex: base.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
Element { id: coinAccSep; content: "'/"; startIndex: coin.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Separator }
Element { id: acc; content: "777"; startIndex: coinAccSep.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
Element { id: accChgSep; content: "'/"; startIndex: acc.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Separator }
Element { id: chg; content: "0"; startIndex: accChgSep.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
Element { id: chgAccIdxSep; content: "/"; startIndex: chg.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Separator }
Element { id: accIdx1; content: "1"; startIndex: chgAccIdxSep.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
Element { id: accIdxSep1; content: "/"; startIndex: accIdx1.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Separator }
Element { id: accIdx2; content: "2"; startIndex: accIdxSep1.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
Element { id: accIdxSep2; content: "/"; startIndex: accIdx2.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Separator }
Element { id: accIdx3; content: "2"; startIndex: accIdxSep2.endIndex; endIndex: startIndex + content.length; contentType: Element.ContentType.Number }
}
}
function test_generateHtml() {
let res = controller.generateHtmlFromElements(testDataElementsComponent.createObject(root).resources)
verify(/^<style>(?:\.[a-zA-Z]{[a-zA-Z0-9#:;]+})+<\/style>(?:<span\sclass=["']\w["']>[\/\d'm]+<\/span>)+$/.test(res), `The generated html is valid and optimum (no extra spaces or CSS long names) - "${res}"`)
}
}
TestCase {
name: "DerivationPathInputRegressionTests"
Component {
id: regressionControlComponent
DerivationPathInput {
initialDerivationPath: "m/44'/60'/0'/0/1"
initialBasePath: "m/44'/60'/0'/0"
}
}
property DerivationPathInput controller: null
// Controller.Component.onCompleted was initializing Component.d.referenceElements after DerivationPathInput.onCompleted was processing the DerivationPathInput.initialDerivationPath, hence the output was wrong (m/44'/60001)
function test_successfulInitializationOfControllerBeforeItem() {
const control = createTemporaryObject(regressionControlComponent, root)
compare("m/44'/60'/0'/0/1", control.derivationPath)
}
}
}