fix(wallet): fix rename account modal states
Considerations: - Change validation mode for StatusText to have validity from the start - Don't show a color selection if the selected color doesn't match the available color palette - Don't enable button if nothing changed - Tests - Add test for validation mode that shows how the valid property behaves based on findings. - Fix text to expect valid on no input for the default control Fixes: #8211
This commit is contained in:
parent
297280c467
commit
16af9dfae6
|
@ -7,19 +7,36 @@ import StatusQ.Controls.Validators 0.1
|
||||||
import StatusQ.TestHelpers 0.1
|
import StatusQ.TestHelpers 0.1
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
width: 300
|
width: 300
|
||||||
height: 100
|
height: 100
|
||||||
|
|
||||||
property int _defaultValidationMode
|
function loadControl(test, sourceComponent) {
|
||||||
|
let testItem = test.createTemporaryObject(sourceComponent, root)
|
||||||
Component.onCompleted: {
|
test.verify(test.waitForRendering(testItem))
|
||||||
_defaultValidationMode = statusInput.validationMode
|
test.mouseClick(testItem)
|
||||||
|
return testItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase {
|
||||||
|
id: regexTC
|
||||||
|
|
||||||
|
property StatusInput testControl: null
|
||||||
|
|
||||||
|
name: "RegexValidationTest"
|
||||||
|
|
||||||
|
when: windowShown
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: defaultComponent
|
||||||
|
|
||||||
StatusInput {
|
StatusInput {
|
||||||
id: statusInput
|
|
||||||
label: "Control under test"
|
label: "Control under test"
|
||||||
charLimit: 30
|
charLimit: 30
|
||||||
placeholderText: `Must match regex(${validators[0].regularExpression.toString()}) and <= 30 chars`
|
placeholderText: `Must match regex(${validators[0].regularExpression.toString()}) and <= 30 chars`
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
validators: [
|
validators: [
|
||||||
|
@ -28,89 +45,124 @@ Item {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
TestCase {
|
|
||||||
id: regexTC
|
|
||||||
|
|
||||||
name: "RegexValidationTest"
|
|
||||||
|
|
||||||
when: windowShown
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test guards
|
// Test guards
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
qtOuput.restartCapturing()
|
qtOuput.restartCapturing()
|
||||||
mouseClick(statusInput)
|
regexTC.testControl = root.loadControl(regexTC, defaultComponent)
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
statusInput.text = ""
|
|
||||||
statusInput.validationMode = _defaultValidationMode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Tests
|
// Tests
|
||||||
function test_initial_empty_is_valid() {
|
function test_initial_empty_is_valid() {
|
||||||
verify(statusInput.valid, "Expected valid input")
|
verify(!regexTC.testControl.valid, "Expected valid input")
|
||||||
|
|
||||||
|
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_regex_validation() {
|
function test_regex_validation() {
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_1)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_1)
|
||||||
verify(statusInput.valid, "Expected valid input")
|
verify(regexTC.testControl.valid, "Expected valid input")
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Ampersand)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_Ampersand)
|
||||||
verify(!statusInput.valid, "Expected invalid input")
|
verify(!regexTC.testControl.valid, "Expected invalid input")
|
||||||
|
|
||||||
|
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_no_invalid_input() {
|
function test_no_invalid_input() {
|
||||||
statusInput.validationMode = StatusInput.ValidationMode.IgnoreInvalidInput
|
regexTC.testControl.validationMode = StatusInput.ValidationMode.IgnoreInvalidInput
|
||||||
|
|
||||||
verify(statusInput.valid, "Expected valid input")
|
verify(regexTC.testControl.valid, "Expected valid input")
|
||||||
verify(statusInput.text.length === 0, "Expected no input")
|
verify(regexTC.testControl.text.length === 0, "Expected no input")
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_2)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_2)
|
||||||
verify(statusInput.valid, "Expected valid input")
|
verify(regexTC.testControl.valid, "Expected valid input")
|
||||||
verify(statusInput.text === "2", "Expect one character")
|
verify(regexTC.testControl.text === "2", "Expect one character")
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Ampersand)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_Ampersand)
|
||||||
verify(statusInput.valid, "Expected invalid input")
|
verify(regexTC.testControl.valid, "Expected invalid input")
|
||||||
verify(statusInput.text === "2", "Expect the same input")
|
verify(regexTC.testControl.text === "2", "Expect the same input")
|
||||||
|
|
||||||
|
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use case expected in case new validation changes are enabled with old unvalid data
|
// Use case expected in case new validation changes are enabled with old invalid data
|
||||||
function test_user_can_delete_initial_invalid_input() {
|
function test_user_can_delete_initial_invalid_input() {
|
||||||
const appendInvalidChars = "#@!*"
|
const appendInvalidChars = "#@!*"
|
||||||
|
|
||||||
statusInput.text = "invalid $" + appendInvalidChars
|
regexTC.testControl.text = "invalid $" + appendInvalidChars
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_End)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_End)
|
||||||
verify(!statusInput.valid, "Expected invalid input due to characters not matching")
|
verify(!regexTC.testControl.valid, "Expected invalid input due to characters not matching")
|
||||||
// Delete invalid characters to get a valid text
|
// Delete invalid characters to get a valid text
|
||||||
for(let i = 0; i < appendInvalidChars.length; ++i)
|
for(let i = 0; i < appendInvalidChars.length; ++i)
|
||||||
TestUtils.pressKeyAndWait(regexTC, statusInput, Qt.Key_Backspace)
|
TestUtils.pressKeyAndWait(regexTC, regexTC.testControl, Qt.Key_Backspace)
|
||||||
verify(statusInput.valid, "Expected valid input")
|
verify(regexTC.testControl.valid, "Expected valid input")
|
||||||
|
|
||||||
|
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase {
|
TestCase {
|
||||||
id: qmlWarnTC
|
id: bindedTC
|
||||||
|
|
||||||
name: "StatusInput"
|
property StatusInput testControl: null
|
||||||
|
|
||||||
|
name: "BindedValuesTest"
|
||||||
when: windowShown
|
when: windowShown
|
||||||
|
|
||||||
|
property QtObject dataObject: QtObject {
|
||||||
|
property string text: "Test text"
|
||||||
|
property string emoji: "👍"
|
||||||
|
property string color: "#FF0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: bindedTextComponent
|
||||||
|
|
||||||
|
StatusInput {
|
||||||
|
charLimit: 10
|
||||||
|
input.isIconSelectable: true
|
||||||
|
placeholderText: qsTr("Enter an account name...")
|
||||||
|
text: bindedTC.dataObject.text
|
||||||
|
input.asset.emoji: bindedTC.dataObject.emoji
|
||||||
|
input.asset.color: bindedTC.dataObject.color
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
validators: [
|
||||||
|
StatusMinLengthValidator {
|
||||||
|
errorMessage: qsTr("You need to enter an account name")
|
||||||
|
minLength: 1
|
||||||
|
},
|
||||||
|
StatusRegularExpressionValidator {
|
||||||
|
regularExpression: /^[^<>]+$/
|
||||||
|
errorMessage: qsTr("This is not a valid account name")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test guards
|
// Test guards
|
||||||
|
|
||||||
function initTestCase() {
|
function init() {
|
||||||
}
|
bindedTC.testControl = root.loadControl(regexTC, bindedTextComponent)
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
statusInput.text = ""
|
|
||||||
statusInput.validationMode = _defaultValidationMode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Tests
|
// Tests
|
||||||
|
function test_assigning_valid_value_works() {
|
||||||
|
qtOuput.restartCapturing()
|
||||||
|
|
||||||
|
verify(!testControl.valid, "Expected input not validated yet")
|
||||||
|
testControl.validationMode = StatusInput.ValidationMode.Always
|
||||||
|
verify(waitForRendering(testControl))
|
||||||
|
verify(testControl.valid, "Expected valid input")
|
||||||
|
bindedTC.dataObject.text = "Test<New"
|
||||||
|
verify(!testControl.valid, "Expected valid input")
|
||||||
|
|
||||||
function test_initial_empty_is_valid() {
|
|
||||||
mouseClick(statusInput)
|
|
||||||
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
verify(qtOuput.qtOuput().length === 0, `No output expected. Found:\n"${qtOuput.qtOuput()}"\n`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ StatusModal {
|
||||||
|
|
||||||
StatusInput {
|
StatusInput {
|
||||||
id: accountNameInput
|
id: accountNameInput
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
input.edit.objectName: "renameAccountNameInput"
|
input.edit.objectName: "renameAccountNameInput"
|
||||||
input.isIconSelectable: true
|
input.isIconSelectable: true
|
||||||
|
@ -56,6 +57,9 @@ StatusModal {
|
||||||
input.asset.emoji: currentAccount.emoji
|
input.asset.emoji: currentAccount.emoji
|
||||||
input.asset.color: currentAccount.color
|
input.asset.color: currentAccount.color
|
||||||
input.asset.name: !currentAccount.emoji ? "filled-account": ""
|
input.asset.name: !currentAccount.emoji ? "filled-account": ""
|
||||||
|
|
||||||
|
validationMode: StatusInput.ValidationMode.Always
|
||||||
|
|
||||||
onIconClicked: {
|
onIconClicked: {
|
||||||
popup.emojiPopup.open()
|
popup.emojiPopup.open()
|
||||||
popup.emojiPopup.x = popup.x + accountNameInput.x + Style.current.padding
|
popup.emojiPopup.x = popup.x + accountNameInput.x + Style.current.padding
|
||||||
|
@ -87,12 +91,12 @@ StatusModal {
|
||||||
if(model[i] === currentAccount.color)
|
if(model[i] === currentAccount.color)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
return -1
|
||||||
}
|
}
|
||||||
onSelectedColorChanged: {
|
onSelectedColorChanged: {
|
||||||
if(selectedColor !== currentAccount.color) {
|
if(selectedColor !== currentAccount.color) {
|
||||||
accountNameInput.input.asset.color = selectedColor
|
accountNameInput.input.asset.color = selectedColor
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +113,8 @@ StatusModal {
|
||||||
text: qsTr("Change Name")
|
text: qsTr("Change Name")
|
||||||
|
|
||||||
enabled: accountNameInput.text !== "" && accountNameInput.valid
|
enabled: accountNameInput.text !== "" && accountNameInput.valid
|
||||||
|
&& (accountNameInput.text !== currentAccount.name
|
||||||
|
|| (accountColorInput.selectedColorIndex >= 0 && accountColorInput.selectedColor !== currentAccount.color))
|
||||||
|
|
||||||
MessageDialog {
|
MessageDialog {
|
||||||
id: changeError
|
id: changeError
|
||||||
|
|
Loading…
Reference in New Issue