Falha no teste da interface do usuário - nenhum elemento nem qualquer descendente tem o foco do teclado no secureTextField

139

Este é o meu caso:

let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.tap()
passwordSecureTextField.typeText("wrong_password") //here is an error

Falha no teste da interface do usuário - nem o elemento nem qualquer descendente têm o foco do teclado. Elemento:

O que está errado? Isso está funcionando bem para o normal textFields, mas o problema surge apenas com secureTextFields. Alguma solução alternativa?

Bartłomiej Semańczyk
fonte
e a parte estranha é que, se eu tentar assim, funciona XCUIApplication (). webViews.secureTextFields ["Senha"]. toque em () XCUIApplication (). webViews.secureTextFields ["Senha"]. typeText ("Welcome")
aurilio
Pode ser que você tenha definido o identificador de acessibilidade, mas não tenha definido isAccessibilityElement = true
soumil
Adicionei uma resposta a uma pergunta semelhante aqui: stackoverflow.com/a/59637897/2585413 . Meu problema foi que eu tinha outras UIWindows com valores .windowLevel incorretos
nteissler

Respostas:

264

Esse problema me causou muita dor, mas consegui descobrir uma solução adequada. No Simulador, verifique se 'Hardware -> Teclado -> Conectar teclado do hardware' está desativado.

Ted Kaminski
fonte
4
Isso corrigiu o problema. Mas é uma solução alternativa muito ruim, pois não podemos aplicá-lo automaticamente para o IC.
Stanislav Pankevich
25
Se você executar seus testes no IC (Jenkins etc.), poderá definir os seguintes parâmetros em um script antes de executar seus testes. "os padrões escrevem com.apple.iphonesimulator ConnectHardwareKeyboard 0"
charlyatwork 12/16/16
7
Isso não resolve o problema para mim. Eu posso ver claramente o campo de texto a obtenção de foco, com o teclado para cima, mas a estrutura de teste nunca pode introduzir texto utilizando o TypeText: Método
Michael
2
Funcionou para mim no Xcode 11, mas desmarcar o teclado de hardware Connect pode não ser suficiente. Além disso, é necessário garantir que o teclado do software seja realmente exibido (na verdade, eu tinha a situação em que nenhum teclado de hardware estava conectado e nenhum teclado de software era exibido, mesmo que o campo de texto tivesse foco e o cursor estivesse piscando).
Reinhard Männer
1
Encontrei isso no Xcode 11 também. Correções localmente, mas como isso pode ser definido no IC?
jherg
26

Recentemente, encontramos um truque para tornar persistente a solução da resposta aceita. Para desativar a configuração do Simulador: 'Hardware -> Teclado -> Conectar teclado do hardware' na linha de comando, deve-se escrever:

defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0

Isso não afetará um simulador em execução - você precisará reiniciar o simulador ou iniciar um novo para que essa configuração tenha efeito.

AlexDenisov
fonte
isso não mudou nada.
Netshark1000
@ netshark1000 que pode ser alterado com a versão mais recente do Xcode, vou verificar.
AlexDenisov
1
extremamente útil, eu precisava do contrário, onde o teclado está sempre ativado, mas sim, isso é ótimo, obrigado. Acabei concordando defaults write com.apple.iphonesimulator ConnectHardwareKeyboard -bool true, mas é o mesmo conceito.
Laser Falcão
2
Eu criei um script em fases de construção para fazer isso. Mas eu precisava matar todos os simuladores, então fiz isso: #killall "Simulator"; defaults write com.apple.iphonesimulator ConnectHardwareKeyboard 0;
Wagner Sales
Isso parece não funcionar mais, a chave mudou? @AlexDenisov
Simon McLoughlin
15

Eu escrevi uma pequena extensão (Swift) que funciona perfeita para mim. Aqui está o código:

extension XCTestCase {

    func tapElementAndWaitForKeyboardToAppear(element: XCUIElement) {
        let keyboard = XCUIApplication().keyboards.element
        while (true) {
            element.tap()
            if keyboard.exists {
                break;
            }
            NSRunLoop.currentRunLoop().runUntilDate(NSDate(timeIntervalSinceNow: 0.5))
        }
    }
}

A idéia principal é continuar tocando em um elemento (campo de texto) antes que o teclado seja apresentado.

berezhnyi oleksandr
fonte
Isso não está funcionando para mim agora. Estou com o Xcode 7.2 (7C68), qual versão você tem? Essa solução que encontramos para o CI funciona para nós: stackoverflow.com/a/34812979/598057 .
Stanislav Pankevich
Para confirmar mais uma vez: esse ajudante funciona para você no campo de texto com senha segura, não apenas no campo de texto normal?
Stanislav Pankevich
Sim, funciona para os dois tipos de campo de texto: regular e seguro.
você precisa saber é o seguinte
1
O problema com esta resposta é que ele usa um atraso codificado. Em vez disso, use o modelo de espera por expectativas com o elemento do teclado.
user1122069
11

Stanislav tem a ideia certa.

Em um ambiente de equipe, você precisa de algo que funcione automaticamente. Eu vim com uma correção aqui no meu blog.

Basicamente, basta colar:

UIPasteboard.generalPasteboard().string = "Their password"
let passwordSecureTextField = app.secureTextFields["password"]
passwordSecureTextField.pressForDuration(1.1)
app.menuItems["Paste"].tap()
RyanPliske
fonte
Obrigado por compartilhar sua solução. Infelizmente, não está funcionando para mim no momento. Estou tendo o Xcode 7.2 (7C68), o que você? Veja outra solução que encontramos para o CI: stackoverflow.com/questions/32184837/… .
Stanislav Pankevich
8

Outra causa desse erro é se houver uma visualização pai do campo de texto no qual você está tentando inserir texto definido como um elemento de acessibilidade ( view.isAccessibilityElement = true). Nesse caso, o XCTest não pode obter um identificador na subvisão para inserir o texto e retornar o erro.

Falha no teste da interface do usuário - nem o elemento nem qualquer descendente têm o foco do teclado.

Não é que nenhum elemento tenha foco (como é possível ver o teclado para cima e o cursor piscando no UITextField), é apenas que nenhum elemento que ele possa alcançar tenha foco. Eu me deparei com isso ao tentar inserir texto em um UISearchBar. A barra de pesquisa em si não é o campo de texto. Ao defini-lo como um elemento de acessibilidade, o acesso ao UITextField subjacente foi bloqueado. Para resolver isso, searchBar.accessibilityIdentifier = "My Identifier"foi definido no UISearchBarentanto isAccessibilityElementnão foi definido como true. Depois disso, teste o código do formulário:

app.otherElements["My Identifier"].tap()
app.otherElements["My Identifier"].typeText("sample text")

Trabalho

user3847320
fonte
6

Isso ocorreu comigo muitas vezes. Você precisa desativar o hardware do teclado e o mesmo layout que o OSX no seu simulador

Hardware / Teclado (desativar tudo)

Depois disso, o software do teclado não será descartado e seus testes poderão digitar texto

Desativar hardware

Fernando Martínez
fonte
5

Durma entre iniciar o aplicativo e digitar dados em campos de texto como este:

sleep(2)

No meu caso, eu continuava recebendo esse erro todas as vezes e apenas essa solução me ajudou.

Kingalione
fonte
1
O problema é que se você tiver um grande número de testes de interface do usuário que executam algo como um login inicial, isso adicionará uma enorme sobrecarga à sua execução de teste de IC.
Delta2flat
4

Talvez isso ajude: eu apenas adicionei uma ação "tap" antes do erro; Isso é tudo :)

[app.textFields[@"theTitle"] tap];
[app.textFields[@"theTitle"] typeText:@"kk"];
Carlos Peralta
fonte
2
Definitivamente, isso não funciona no campo de texto de senha segura.
Stanislav Pankevich
Isso funcionou muito bem no meu campo de texto de senha segura. Boa solução.
Travis M.
4
func pasteTextFieldText(app:XCUIApplication, element:XCUIElement, value:String, clearText:Bool) {
    // Get the password into the pasteboard buffer
    UIPasteboard.generalPasteboard().string = value

    // Bring up the popup menu on the password field
    element.tap()

    if clearText {
        element.buttons["Clear text"].tap()
    }

    element.doubleTap()

    // Tap the Paste button to input the password
    app.menuItems["Paste"].tap()
}
Anthony
fonte
4

Grave o estojo da maneira que desejar, com ou sem o teclado conectado. Mas faça o seguinte antes de jogar o teste.

Esta opção a seguir (conectar o teclado do hardware) deve estar desmarcada durante a execução do teste.

insira a descrição da imagem aqui

umairhhhs
fonte
4

No meu caso, este Hardware -> Keyboard -> Connect Hardware Keyboard-> Disable não funcionou para mim.

Mas quando eu segui

1) Hardware -> Keyboard -> Connect Hardware Keyboard-> Ativado e execute o aplicativo
2) Hardware -> Keyboard -> Connect Hardware Keyboard-> Desativar .

Funcionou para mim

BharathRao
fonte
Trabalhou para mim, HOMEM Eu odeio esse aspecto do XCode!
bwobbones 30/06
3

[ Reposicionando o comentário de Bartłomiej Semańczyk como resposta, porque resolveu o problema para mim]

Eu precisava fazer o Simulador> Redefinir conteúdo e configurações na barra de menus do simulador para fazer isso começar a funcionar para mim.

rogueleaderr
fonte
Redefinir o simulador também me ajudou. Curiosamente, o problema ocorreu apenas no simulador, enquanto o mesmo teste (toque em texfield seguido de digitação de caracteres) funcionou bem em um dispositivo.
Christian
1

Em algum momento, os campos de texto não são implementados como campos de texto ou são agrupados em outro elemento da interface do usuário e não são facilmente acessíveis. Aqui está uma solução alternativa:

//XCUIApplication().scrollViews.otherElements.staticTexts["Email"] the locator for the element
RegistrationScreenStep1of2.emailTextField.tap()
let keys = app.keys
 keys["p"].tap() //type the keys that you need
 
 //If you stored your data somewhere and need to access that string //you can cats your string to an array and then pass the index //number to key[]
 
 let newUserEmail = Array(newPatient.email())
 let password = Array(newPatient.password)
 
 //When you cast your string to an array the elements of the array //are Character so you would need to cast them into string otherwise //Xcode will compain. 
 
 let keys = app.keys
     keys[String(newUserEmail[0])].tap()
     keys[String(newUserEmail[1])].tap()
     keys[String(newUserEmail[2])].tap()
     keys[String(newUserEmail[3])].tap()
     keys[String(newUserEmail[4])].tap()
     keys[String(newUserEmail[5])].tap()       

Eugene Berezin
fonte
0

Sua primeira linha é apenas uma definição de consulta , o que não significa que passwordSecureTextFieldrealmente existiria.

Sua segunda linha executará dinamicamente a consulta e tentará (re) vincular a consulta ao elemento da interface do usuário. Você deve colocar um ponto de interrupção e verificar se um e apenas um elemento foi encontrado. Ou apenas use uma declaração:

XCTAssertFalse(passwordSecureTextField.exists);

Caso contrário, parece ok, tapdeve forçar o teclado visível e typeTextdeve funcionar. O log de erros deve informar mais informações.

JOM
fonte
1
passwordSecureTextFieldexiste. Corrigi o problema, limpando a memória e reescrevendo essas linhas novamente. Estranho, mas funcionou.
Bartłomiej Semańczyk
É bom ouvir que está consertado! Eu me deparo com problema semelhante ontem com beta 6 :)
JOM
beta 6? :-) realmente? Tenho apenas 5 :)
Bartłomiej Semańczyk
Você está ocupado codificando :) O Beta 6 não gravou tappara mim, demorou algum tempo para descobrir. Boa prática de depuração!
JOM
Talvez você saiba a resposta para isso: stackoverflow.com/questions/32219015/… ?
Bartłomiej Semańczyk
0

Não erre, o problema é que você gravou seu tempo de teste, seu aplicativo conectará o teclado do hardware enquanto o simulador automático de tempo de teste usa apenas o teclado do software. Então, para saber como corrigir esses problemas. Basta usar o teclado do software no seu tempo de gravação. você pode ver a magia.

codercat
fonte
0

O problema para mim era o mesmo que para Ted. Na verdade, se o campo de senha for tocado após o campo de login e a KB de hardware estar ativada, o teclado do software será descartado no segundo toque de campo e não será específico para os testes da interface do usuário.

Depois de algum tempo brincando com o AppleScript, eis o que eu criei (melhorias são bem-vindas):

tell application "Simulator" activate tell application "System Events" try tell process "Simulator" tell menu bar 1 tell menu bar item "Hardware" tell menu "Hardware" tell menu item "Keyboard" tell menu "Keyboard" set menuItem to menu item "Connect Hardware Keyboard" tell menu item "Connect Hardware Keyboard" set checkboxStatus to value of attribute "AXMenuItemMarkChar" of menuItem if checkboxStatus is equal to "✓" then click end if end tell end tell end tell end tell end tell end tell end tell on error tell application "System Preferences" activate set securityPane to pane id "com.apple.preference.security" tell securityPane to reveal anchor "Privacy_Accessibility" display dialog "Xcode needs Universal access to disable hardware keyboard during tests(otherwise tests may fail because of focus issues)" end tell end try end tell end tell

Crie um arquivo de script com o código acima e adicione-o aos destinos necessários (provavelmente apenas testes de interface do usuário, você pode adicionar scripts semelhantes aos seus destinos de desenvolvimento para reativar o teclado HW durante o desenvolvimento). Você deve adicionar a Run Scriptfase nas fases de construção e usá-lo desta forma: osascript Path/To/Script/script_name.applescript

Timur Kuchkarov
fonte
0

Encontramos o mesmo erro ao definir o accessibilityIdentifiervalor para uma visualização personalizada ( UIStackViewsubclasse) contendo UIControlsubvisões. Nesse caso, o XCTest não conseguiu obter o foco do teclado para os elementos descendentes.

Nossa solução foi simplesmente remover a accessibilityIdentifiervisualização principal e definir accessibilityIdentifieras subvisões por meio de propriedades dedicadas.

shadowhorst
fonte
0

Outra resposta, mas para nós o problema era que a visão estava muito próxima de outra visão que um reconhecedor de gestos nela. Descobrimos que precisávamos que a exibição estivesse a pelo menos 20 pixels de distância (no nosso caso abaixo). Literalmente 15 não funcionaram e 20 ou mais funcionaram. Isso é estranho, admito, mas tivemos alguns UITextViews que estavam funcionando e outros que não estavam e todos estavam sob o mesmo pai e outro posicionamento idêntico (e nomes de variáveis, é claro). O teclado ligado ou desligado ou o que quer que não faça diferença. Acessibilidade mostrou os campos. Nós reiniciamos nossos computadores. Fizemos construções limpas. Checkouts de fontes novas.

David J
fonte
0

O que corrigiu esse problema para mim foi adicionar um segundo de sono:

let textField = app.textFields["identifier"]
textField.tap()
sleep(1)
textField.typeText(text)
Przemysław Wrzesiński
fonte
0

Corri para esse problema e pude corrigi-lo no meu cenário, pegando a solução postada por @AlexDenisov e adicionando-a às minhas pré-ações para executar e testar .

insira a descrição da imagem aqui

CodeBender
fonte
0

Não há necessidade de ligar / desligar o teclado na E / S. Não use .typeText para secureTextField, basta usar

app.keys["p"].tap()
app.keys["a"].tap()
app.keys["s"].tap()
app.keys["s"].tap()

Bônus: você obtém o som do teclado, clique :)

zdravko zdravkin
fonte
0

Por fim, escrevi um script que edita o arquivo .plist do Simulator e define a ConnectHardwareKeyboardpropriedade como false para o simulador selecionado. Você ouviu direito, ele altera a propriedade do simulador especificamente selecionado no dicionário "DevicePreferences", em vez de editar a propriedade global.

Primeiro, crie um script de shell chamado disable-hardware-keyboard.sh com o seguinte conteúdo. Você pode colocá-lo em "YourProject / xyzUITests / Scripts /":

echo "Script: Set ConnectHardwareKeyboard to false for given Simulator UDID"

if [[ $1 != *-*-*-*-* ]]; then
    echo "Pass device udid as first argument."
    exit 1
else
    DEVICE_ID=$1
fi

DEVICE_PREFERENCES_VALUE='<dict><key>ConnectHardwareKeyboard</key><false/></dict>'
killall Simulator # kill restart the simulator to make the plist changes picked up
defaults write com.apple.iphonesimulator DevicePreferences -dict-add $DEVICE_ID $DEVICE_PREFERENCES_VALUE
open -a Simulator # IMPORTANT

Agora siga estas etapas para chamá-lo passando o udid do simulador selecionado como argumento:

  1. Edite seu esquema Xcode (ou a interface do usuário testa o esquema específico, se você tiver um)
  2. Vá para: Teste> Pré-ações
  3. Adicione um novo script tocando no símbolo "+"> "Nova ação de execução de script".
  4. Importante: no menu suspenso "Fornecer configurações de compilação de", escolha seu destino principal do aplicativo, não o destino dos testes de interface do usuário.
  5. Agora adicione o seguinte script na área de texto abaixo.

Script dentro de Teste> Pré-ações:

#!/bin/sh
# $PROJECT_DIR is path to your source project. This is provided when we select "Provide build settings from" to "AppTarget"
# $TARGET_DEVICE_IDENTIFIER is the UDID of the selected simulator
sh $PROJECT_DIR/xyzUITests/Scripts/disable-hardware-keyboard.sh $TARGET_DEVICE_IDENTIFIER

# In order to see output of above script, append following with it:
#  | tee ~/Desktop/ui-test-scheme-prescript.txt

Hora de testá-lo:

  1. Simulador de lançamento
  2. Ativar teclado de hardware para ele
  3. Execute qualquer teste de interface do usuário com a interação do teclado. Observe que o simulador reinicia e o teclado do hardware está desativado. E a interação do teclado do teste está funcionando bem. :)
Hasaan Ali
fonte
-1

Teve o mesmo problema com os Securetextfields. A opção de conexão de hardware no meu Simulador era de, mas ainda estava com o problema. Finalmente, isso funcionou para mim (Swift 3):

 let enterPasswordSecureTextField = app.secureTextFields["Enter Password"]
    enterPasswordSecureTextField.tap()
    enterPasswordSecureTextField.typeText("12345678")
Rads
fonte
Qual é a diferença entre o seu código e o código solicitado na pergunta.
Shivam Pokhriyal