status-desktop/storybook/qmlTests/tests/tst_EnterSeedPhrase.qml

454 lines
22 KiB
QML
Raw Permalink Normal View History

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQml 2.15
import QtQml.Models 2.15
import StatusQ 0.1
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)
}
// regression test for https://github.com/status-im/status-desktop/issues/16291
function test_threeLetterPrefixSuggestionInput() {
const commonPrefixToTest = "cat"
//generate a seed phrase
const expectedSeedPhrase = ["abandon", "ability", "able", "about", "above", "absent", "absorb", "abstract", "absurd", "abuse", "access", commonPrefixToTest]
const baseDictionary = [...expectedSeedPhrase, "cow", "catalog", "catch", "category", "cattle"]
let isSeedPhraseValidCalled = false
itemUnderTest.isSeedPhraseValid = (seedPhrase) => {
verify(seedPhrase === expectedSeedPhrase.join(" "), "Seed phrase is not valid")
isSeedPhraseValidCalled = true
return true
}
itemUnderTest.dictionary.append(baseDictionary.map((word) => ({seedWord: word})))
//Type the seed phrase except the last word
const str = expectedSeedPhrase.join(" ")
for (let i = 0; i < str.length - commonPrefixToTest.length; i++) {
keyPress(str.charAt(i))
}
const lastInputField = findChild(itemUnderTest, "enterSeedPhraseInputField12")
verify(!!lastInputField)
mouseClick(lastInputField)
tryCompare(lastInputField, "activeFocus", true)
// type the common prefix -> "cat..."
keyClick(Qt.Key_C)
keyClick(Qt.Key_A)
keyClick(Qt.Key_T)
tryCompare(lastInputField, "text", "cat")
// hit Enter to accept "cat"
keyClick(Qt.Key_Enter)
verify(isSeedPhraseValidCalled, "isSeedPhraseValid was not called")
// hit Enter to submit the form
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")
}
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})))
ClipboardUtils.setText(expectedSeedPhrase.join(" "))
// 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})))
ClipboardUtils.setText(expectedSeedPhrase.join(" "))
// 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)
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")
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")
}
}
}