mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-09 13:56:10 +00:00
8a69f3bc63
* fix(SeedPhrase): Fixing seed phrase validation 1. Validate each word after the editing is finished 2. Fixing the seed phrase suggestions where the suggestions box was hidden behind other ui elements 3. Propagate editingFinished signal in StatusBaseInput, StatusInput, StatusSeedPhraseInput 4. Fixing undefined `mnemonicIndex` errors * fix: Refactoring of SeedPhraseInputView Remove duplicated code and use EnterSeedPhrase component + Added storybook page * fix(Onboarding): Fixing seed phrase validation on windows The seed phrase validation fails on windows due to the dictionary line endings * chore(squish): Update e2e tests to the new enter seed phrase panel construction * fix: Load english dictionary from local file using StringUtils
414 lines
20 KiB
QML
414 lines
20 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Controls 2.15
|
|
import QtQml 2.15
|
|
import QtQml.Models 2.15
|
|
|
|
import StatusQ.Core.Utils 0.1
|
|
|
|
import QtTest 1.15
|
|
|
|
import shared.panels 1.0
|
|
import utils 1.0
|
|
|
|
Item {
|
|
id: root
|
|
width: 600
|
|
height: 400
|
|
|
|
TestCase {
|
|
name: "EnterSeedPhraseTest"
|
|
when: windowShown
|
|
|
|
Component {
|
|
id: enterSeedPhraseComponent
|
|
EnterSeedPhrase {
|
|
id: enterSeedPhrase
|
|
anchors.fill: parent
|
|
dictionary: ListModel {}
|
|
|
|
readonly property SignalSpy submitSpy: SignalSpy { target: enterSeedPhrase; signalName: "submitSeedPhrase" }
|
|
readonly property SignalSpy seedPhraseUpdatedSpy: SignalSpy { target: enterSeedPhrase; signalName: "seedPhraseUpdated" }
|
|
}
|
|
}
|
|
|
|
property EnterSeedPhrase itemUnderTest: null
|
|
|
|
function generateDictionaryVariation(baseDictionary) {
|
|
let dictionaryVariation = baseDictionary.map((word) => word + "a")
|
|
dictionaryVariation = baseDictionary.map((word) => word + "b").concat(dictionaryVariation)
|
|
dictionaryVariation = baseDictionary.map((word) => word + "c").concat(dictionaryVariation)
|
|
dictionaryVariation = baseDictionary.map((word) => word + "d").concat(dictionaryVariation)
|
|
dictionaryVariation.sort()
|
|
return dictionaryVariation
|
|
}
|
|
|
|
function init() {
|
|
itemUnderTest = createTemporaryObject(enterSeedPhraseComponent, root)
|
|
waitForItemPolished(itemUnderTest)
|
|
waitForRendering(itemUnderTest)
|
|
}
|
|
|
|
function test_componentCreation() {
|
|
verify(itemUnderTest !== null, "Component creation failed")
|
|
}
|
|
|
|
// Test seed phrase input by typing on the keyboard
|
|
// The seed phrase is valid and the typing is done without any space between words
|
|
// This is the most common way to input a seed phrase
|
|
function test_seedPhraseKeyboardInput() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
expectedSeedPhrase.sort();
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(expectedSeedPhrase.map((word) => ({seedWord: word})))
|
|
|
|
//Type the seed phrase. No space is needed between words
|
|
const str = expectedSeedPhrase.join("")
|
|
for (let i = 0; i < str.length; i++) {
|
|
keyPress(str.charAt(i))
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 1, "submitSeedPhrase signal was not emitted")
|
|
// This signal is emitted multiple times due to the way the seed phrase is updated and validated
|
|
// The minimum is the length if the seed phrase
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by typing on the keyboard
|
|
// The seed phrase is valid and the typing is done with a space between words
|
|
// The space between words is ignored and the seed should be valid
|
|
function test_seedPhraseKeyboardInputWithExtraSpace() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
expectedSeedPhrase.sort();
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(expectedSeedPhrase.map((word) => ({seedWord: word})))
|
|
|
|
//Type the seed phrase. A space is needed between words
|
|
const str = expectedSeedPhrase.join(" ")
|
|
for (let i = 0; i < str.length; i++) {
|
|
keyPress(str.charAt(i))
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
keyClick(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 1, "submitSeedPhrase signal was not emitted")
|
|
// This signal is emitted multiple times due to the way the seed phrase is updated and validated
|
|
// The minimum is the length if the seed phrase
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by pasting from clipboard
|
|
// The seed phrase is valid and the clipboard seed is space separated
|
|
function test_seedPhrasePaste() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
|
|
expectedSeedPhrase.sort();
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(expectedSeedPhrase.map((word) => ({seedWord: word})))
|
|
|
|
const clipboardHelper = createTemporaryQmlObject("import QtQuick 2.15; QtObject { property var getFromClipboard }", root)
|
|
clipboardHelper.getFromClipboard = () => expectedSeedPhrase.join(" ")
|
|
Utils.globalUtilsInst = clipboardHelper
|
|
|
|
// Trigger the paste action
|
|
keyClick("v", Qt.ControlModifier)
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 1, "submitSeedPhrase signal was not emitted")
|
|
// This signal is emitted multiple times due to the way the seed phrase is updated and validated
|
|
// The minimum is the length if the seed phrase
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test the seed phrase by choosing from the suggestions
|
|
// The seed phrase is valid and the user selects the words from the suggestions
|
|
function test_seedPhraseChooseFromSuggestions() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
// Suggestions dialog is expected to receive key events when there's multiple suggestions
|
|
let downKeyEvents = 0
|
|
for (let i = 0; i < expectedSeedPhrase.length; i++) {
|
|
keySequence(expectedSeedPhrase[i].substring(0, 4).split('').join(','))
|
|
for (let j = 0; j < downKeyEvents; j++) {
|
|
keyClick(Qt.Key_Down)
|
|
}
|
|
downKeyEvents = downKeyEvents === 3 ? 0 : downKeyEvents + 1
|
|
keyClick(Qt.Key_Tab)
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
keyPress(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 1, "submitSeedPhrase signal was not emitted")
|
|
// This signal is emitted multiple times due to the way the seed phrase is updated and validated
|
|
// The minimum is the length if the seed phrase
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by typing on the keyboard
|
|
// The seed phrase is invalidated by the external isSeedPhraseValid
|
|
function test_invalidatedSeedPhraseKeyboardInput() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return false
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
//Type the seed phrase
|
|
const str = expectedSeedPhrase.join("")
|
|
for (let i = 0; i < str.length; i++) {
|
|
keyPress(str.charAt(i))
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 0, "submitSeedPhrase signal was emitted")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by pasting from clipboard
|
|
// The seed phrase is invalidated by the external isSeedPhraseValid
|
|
function test_invalidatedSeedPhrasePaste() {
|
|
//generate a seed phrase
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return false
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
const clipboardHelper = createTemporaryQmlObject("import QtQuick 2.15; QtObject { property var getFromClipboard }", root)
|
|
clipboardHelper.getFromClipboard = () => expectedSeedPhrase.join(" ")
|
|
Utils.globalUtilsInst = clipboardHelper
|
|
|
|
// Trigger the paste action
|
|
keyClick("v", Qt.ControlModifier)
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
verify(itemUnderTest.submitSpy.count === 0, "submitSeedPhrase signal was emitted")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by typing on the keyboard
|
|
// The seed phrase is invalid due to the length
|
|
function test_invalidLengthSeedPhrase() {
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
//Type the seed phrase
|
|
const str = expectedSeedPhrase.join("")
|
|
for (let i = 0; i < str.length; i++) {
|
|
keyPress(str.charAt(i))
|
|
}
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
verify(!isSeedPhraseValidCalled, "isSeedPhraseValid was called when it should not have been")
|
|
verify(itemUnderTest.submitSpy.count === 0, "submitSeedPhrase signal was emitted")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test seed phrase input by typing on the keyboard
|
|
// The seed phrase is invalid due to the dictionary word
|
|
function test_invalidDictionarySeedPhrase() {
|
|
const expectedSeedPhrase = ["abandonna", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
// ^^ invalid word
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
//Type the seed phrase
|
|
const str = expectedSeedPhrase.join("")
|
|
for (let i = 0; i < str.length; i++) {
|
|
keyPress(str.charAt(i))
|
|
if (i === 8) {
|
|
// The first word is invalid. Move on to the next word
|
|
keyPress(Qt.Key_Tab)
|
|
}
|
|
}
|
|
|
|
keyClick(Qt.Key_Enter)
|
|
print (itemUnderTest.seedPhraseUpdatedSpy.count)
|
|
verify(itemUnderTest.submitSpy.count === 0, "submitSeedPhrase signal was emitted")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
}
|
|
|
|
// Test suggestions are active after the seed phrase word is updated
|
|
function test_suggestionsActiveAfterUpdatingWord() {
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidentd"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
let lastVerifiedSeedPhrase = ""
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
lastVerifiedSeedPhrase = seedPhrase
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
// Suggestions dialog is expected to receive key events when there's multiple suggestions
|
|
let downKeyEvents = 0
|
|
for (let i = 0; i < expectedSeedPhrase.length; i++) {
|
|
keySequence(expectedSeedPhrase[i].substring(0, 4).split('').join(','))
|
|
for (let j = 0; j < downKeyEvents; j++) {
|
|
keyClick(Qt.Key_Down)
|
|
}
|
|
downKeyEvents = downKeyEvents === 3 ? 0 : downKeyEvents + 1
|
|
keyClick(Qt.Key_Tab)
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
|
|
isSeedPhraseValidCalled = false
|
|
|
|
keyPress(Qt.Key_Backspace)
|
|
wait (500) // Wait for the suggestions to appear
|
|
keyClick(Qt.Key_Tab)
|
|
keyClick(Qt.Key_Enter)
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
print (lastVerifiedSeedPhrase)
|
|
verify(lastVerifiedSeedPhrase === expectedSeedPhrase.join(" ").slice(0, -1) + "a", "Seed phrase is not updated")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
|
|
}
|
|
|
|
// Test suggestions are active after the seed phrase word is fixed
|
|
function test_suggestionsActiveAfterFixingWord() {
|
|
const expectedSeedPhrase = ["abandona", "abilityb", "ablec", "aboutd", "abovea", "absentb", "absorbc", "abstractd", "absurda", "abuseb", "accessc", "accidenntd"]
|
|
expectedSeedPhrase.sort()
|
|
|
|
const baseDictionary = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", "accident"]
|
|
let dictionaryVariation = generateDictionaryVariation(baseDictionary)
|
|
|
|
let isSeedPhraseValidCalled = false
|
|
let lastVerifiedSeedPhrase = ""
|
|
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
|
|
lastVerifiedSeedPhrase = seedPhrase
|
|
isSeedPhraseValidCalled = true
|
|
return true
|
|
}
|
|
|
|
itemUnderTest.dictionary.append(dictionaryVariation.map((word) => ({seedWord: word})))
|
|
|
|
// Suggestions dialog is expected to receive key events when there's multiple suggestions
|
|
let downKeyEvents = 0
|
|
for (let i = 0; i < expectedSeedPhrase.length; i++) {
|
|
keySequence(expectedSeedPhrase[i].substring(0, 4).split('').join(','))
|
|
for (let j = 0; j < downKeyEvents; j++) {
|
|
keyClick(Qt.Key_Down)
|
|
}
|
|
downKeyEvents = downKeyEvents === 3 ? 0 : downKeyEvents + 1
|
|
keyClick(Qt.Key_Tab)
|
|
}
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid is not called")
|
|
|
|
isSeedPhraseValidCalled = false
|
|
|
|
for (let i = 0; i < 2; i++) {
|
|
keyPress(Qt.Key_Backspace)
|
|
}
|
|
|
|
wait (500) // Wait for the suggestions to appear
|
|
keyClick(Qt.Key_Tab)
|
|
keyClick(Qt.Key_Enter)
|
|
|
|
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
|
|
verify(lastVerifiedSeedPhrase === expectedSeedPhrase.join(" ").slice(0, -3) + "ta", "Seed phrase is not updated")
|
|
verify(itemUnderTest.seedPhraseUpdatedSpy.count >= expectedSeedPhrase.length, "seedPhraseUpdate signal was not emitted")
|
|
verify(itemUnderTest.submitSpy.count === 1, "submitSeedPhrase signal was emitted")
|
|
}
|
|
}
|
|
}
|