Webdriverio: Solicitação de recurso: forneça waitForInvisible etc. para tornar o código claro

Criado em 20 set. 2017  ·  33Comentários  ·  Fonte: webdriverio/webdriverio

Ninguém vê waitForVisible(..., ..., true) , pela primeira vez pensaria que os true meios para realmente esperar até o elemento de dado é visível, e até eu ficar confuso lendo ou escrevendo meus testes vezes ( "porque am Estou esperando que essa coisa se torne visível e não invisível? Ah certo, a verdadeira bandeira significa fazer o oposto ... ")

É um exemplo perfeito de código pouco claro (argumentos booleanos quase sempre são). Não acho que alguém preferiria o argumento reverse vez de waitForInvisible(...) ou waitFor('invisible', ...) ou waitForVisibility(..., {visible: false}) .

É claro que podemos escrever facilmente nossa própria função waitForInvisible , mas tenha em mente que, como essa função não existe na API do webdriver, nem todos estarão inclinados a escrever sua própria função, e muitos códigos na natureza será menos legível como resultado.

Pensamentos?

Discussion

Comentários muito úteis

Tendo trabalhado com muitos desenvolvedores agora na escrita de testes WebdriverIO, isso sempre surge, de duas maneiras:

  1. Um desenvolvedor que escreve um teste precisa da funcionalidade reversa e não encontra o argumento booleano nos documentos da API, então escreve seu próprio código waitUntil diretamente no teste (problema: descoberta)

    • Alguns desenvolvedores são muito úteis e escrevem um ajudante para ele - o que é bom, mas já vi repositórios com 3-4 ajudantes fazendo a mesma coisa, com nomes ligeiramente diferentes: waitForNotVisible , waitUntilNotVisible , etc. (problema: duplicação, fragmentação)

  2. Um desenvolvedor que escreve um teste aprende sobre o argumento booleano, mas também sabe que é confuso, então adiciona um comentário em todos os lugares em que o usa - se eles forem bons desenvolvedores (problema: boilerplate)
  3. Um desenvolvedor lendo um teste não entende o que o booleano significa e assume o óbvio "eles estão esperando que este elemento {exista, seja visível, etc}" (problema: compreensibilidade)

Os desenvolvedores que vi cometer esses erros variam de totalmente novos a especialistas experientes, o que é um sinal claro para mim de que a API está quebrada, não é um problema educacional. Uma boa API pode ser descoberta e comunica claramente a intenção do desenvolvedor quando ele escreveu o código; Acho que os problemas que vi sugerem fortemente que não é o caso aqui. A antiga máxima de design de software "o código é escrito uma vez e lido muitas vezes" é muito relevante aqui.

Sou extremamente simpático ao argumento de "não explodir a API", mas a) o argumento booleano FAZ parte da API - apenas uma maneira muito confusa e pouco detectável de fazer isso eb) a necessidade de "reverter "essas operações são tão incrivelmente comuns que ter métodos de nível superior para os comportamentos é uma API incrivelmente valiosa (e sem ela é muito doloroso para os desenvolvedores do mundo real).

Eu também discordo do argumento escorregadio de @ mmcculloch15 de que adicionar API de nível superior para reverter os métodos wait… implica que precisaríamos adicionar API de nível superior para reverter os métodos is… : inverter os métodos is… são o comportamento básico de inversão booleana embutido em JS (use ! ); isso não é verdade para os comportamentos de wait… que requerem uma função personalizada para serem revertidos. Eu sou 100% a favor de adicionar waitForInvisible e 0% a favor de adicionar isNotVisible .

Todos 33 comentários

Tenho que concordar aqui, a API atual é contra-intuitiva e requer comentários para uma boa manutenção do código.

Pior ainda, você também precisa declarar novamente o tempo limite.

Pior ainda, você também precisa declarar novamente o tempo limite.

Não vejo por que você tem que declarar novamente o tempo limite. Você pode apenas fazer $('.hiddenElement').waitForVisible(null, true) . Eu pessoalmente não vejo necessidade de adicionar comandos para isso. Especialmente porque você também pode escrever como

browser.waitUntil(() => $('elem').isVisible())

Estou aberto a outras opiniões.

OK, usar null é um pouco melhor, mas me colocar no lugar de qualquer um que vai olhar o código no futuro - o que exatamente isso significa?

Estou polvilhando comentários como este no momento.

.waitForVisible(submit, null, true) //boolean indicates 'waitForInvisible' test.

Não tenho certeza de como o exemplo que você deu melhora a legibilidade, a menos que houvesse um método isInvisible?

Eu pessoalmente criei alguns ajudantes especialmente por causa deste https://github.com/ubccr/xdmod/tree/xdmod7.1/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers

Fiz isso para que estagiários e outros pudessem facilmente saber, em vez de passar um verdadeiro contra-intuitivo para waitForVisible. Se fosse waitForVisible (, false), faria um pouco mais de sentido

Mas eu prefiro o waitForInvisible / waitUntilNotExist

No entanto, uma vez que estamos debatendo isso, acho que devemos escolher um ou outro de waitFor vs waitAté que sejam iguais, mas ter os dois sempre me incomodou. Eu nunca sei qual devo usar

Na minha opinião, espere até> waitFor

Na minha opinião, espere até> waitFor

Não tenho certeza do que você quis dizer com isso, mas esses são apenas métodos de espera diferentes. Com waitUntil você pode esperar por coisas arbitrárias, enquanto waitForVisible obviamente só verifica a visibilidade.

Meu exemplo acima estava errado, deveria ser:

browser.waitUntil(() => $('elem').isVisible() === false)

esperar até que um elemento __não__ esteja visível. Meu problema com a adição de comandos é que isso explode a API sem adicionar nenhum valor. Qualquer pessoa é livre para criar métodos auxiliares para aumentar a legibilidade.

Obrigado @ christian-bromann essa é uma boa solução.

Não tenho certeza do que você quis dizer com isso, mas esses são apenas métodos de espera diferentes. Com waitUntil você pode esperar por coisas arbitrárias, enquanto waitForVisible obviamente só verifica a visibilidade.

Isso faz sentido, estava faltando o raciocínio.

Eu apenas quis dizer, de uma perspectiva de leitura, waitUntil parece melhor do que waitFor, embora de uma perspectiva de escrita, waitFor seja mais curto :)

Acho que é inegavelmente verdade que elem.waitForInvisible() seria mais legível do que elem.waitForVisible(null, true) . Também é verdade que a maioria das pessoas que se deparam com isso no código precisará verificar a API para descobrir o que está acontecendo. Acho que o ponto de legibilidade é válido, com certeza. Também não é algo que consome muita energia mental depois de verificar a API de um dos métodos waitForXYZ . Agora que tenho esse entendimento, gosto de poder usar o mesmo método para os cenários normal e reverso.

Se você seguiu o caminho de ter métodos separados para todos os cenários reversos, provavelmente também precisaria incluir isInvisible() e isNotEnabled() logo depois, o que está chegando a cerca de 10 novos métodos aditivos. Eu gosto da solução do método auxiliar também, se você quiser que as coisas sejam um pouco mais explícitas, se for necessário para a sua situação.

Minha preferência pessoal seria definitivamente para uma API que também adicionaria a opção de passar parâmetros ao longo das linhas de {reverse: True, timeout: 5000}.

@ christian-bromann, o que importa aqui é que você tem que admitir que alguém está vendo o seguinte código pela primeira vez:

  await browser.waitForExist('#loginForm', 5000, true)

Ficaria totalmente surpreso ao descobrir que significa "esperar para não existir".

@MattyBalaam ser capaz de passar {reverse: true} é um pouco melhor, mas ainda é horrível do ponto de vista da obviedade.

Eu escrevi algumas funções de helpers para este propósito, chamei-as de waitForElementToGo , sinta-se à vontade para usá-las em seus scripts de automação https://www.npmjs.com/package/wdio-helpers

@ christian-bromann Se não vamos mudar a api no V5 - digo que encerramos este assunto.

Tendo trabalhado com muitos desenvolvedores agora na escrita de testes WebdriverIO, isso sempre surge, de duas maneiras:

  1. Um desenvolvedor que escreve um teste precisa da funcionalidade reversa e não encontra o argumento booleano nos documentos da API, então escreve seu próprio código waitUntil diretamente no teste (problema: descoberta)

    • Alguns desenvolvedores são muito úteis e escrevem um ajudante para ele - o que é bom, mas já vi repositórios com 3-4 ajudantes fazendo a mesma coisa, com nomes ligeiramente diferentes: waitForNotVisible , waitUntilNotVisible , etc. (problema: duplicação, fragmentação)

  2. Um desenvolvedor que escreve um teste aprende sobre o argumento booleano, mas também sabe que é confuso, então adiciona um comentário em todos os lugares em que o usa - se eles forem bons desenvolvedores (problema: boilerplate)
  3. Um desenvolvedor lendo um teste não entende o que o booleano significa e assume o óbvio "eles estão esperando que este elemento {exista, seja visível, etc}" (problema: compreensibilidade)

Os desenvolvedores que vi cometer esses erros variam de totalmente novos a especialistas experientes, o que é um sinal claro para mim de que a API está quebrada, não é um problema educacional. Uma boa API pode ser descoberta e comunica claramente a intenção do desenvolvedor quando ele escreveu o código; Acho que os problemas que vi sugerem fortemente que não é o caso aqui. A antiga máxima de design de software "o código é escrito uma vez e lido muitas vezes" é muito relevante aqui.

Sou extremamente simpático ao argumento de "não explodir a API", mas a) o argumento booleano FAZ parte da API - apenas uma maneira muito confusa e pouco detectável de fazer isso eb) a necessidade de "reverter "essas operações são tão incrivelmente comuns que ter métodos de nível superior para os comportamentos é uma API incrivelmente valiosa (e sem ela é muito doloroso para os desenvolvedores do mundo real).

Eu também discordo do argumento escorregadio de @ mmcculloch15 de que adicionar API de nível superior para reverter os métodos wait… implica que precisaríamos adicionar API de nível superior para reverter os métodos is… : inverter os métodos is… são o comportamento básico de inversão booleana embutido em JS (use ! ); isso não é verdade para os comportamentos de wait… que requerem uma função personalizada para serem revertidos. Eu sou 100% a favor de adicionar waitForInvisible e 0% a favor de adicionar isNotVisible .

@chrishyle Acabei de lidar com esta questão

Oferecemos addCommand como um recurso e é ridiculamente fácil implementar seu próprio waitForInvisible (), waitForNotVisible () ou o que você quiser nomear.

browser.addCommand ('waitForInvisible', função (tempo limite, mensagem) {
this.waitForDisplayed (tempo limite, verdadeiro, mensagem);
},verdade);

@abjerstedt obrigado pela resposta rápida! Definitivamente não seria a primeira vez que pensaria demais em algo, mas, mesmo assim, não tenho certeza se isso me faz estar errado sobre isso. = P

Implícito em sua resposta está: "você está certo, isso surge o tempo todo" - então acho que concordamos que é muito comum e talvez até concordemos que o booleano mágico é uma solução ruim . A verdadeira resposta que você tem para este problema não é o booleano, mas "escreva seu próprio ajudante" - o que significa que a "prática recomendada" para cada usuário WebdriverIO, em todo o seu ecossistema, é escrever o código por conta própria ... expandindo de fato a API, mas de forma clichê e fragmentada. Você puniu a responsabilidade de resolver isso para seus usuários = (. Para complicar ainda mais, é a mensagem bastante consistente de @cristian-bromann de que não devemos usar addCommand ... então ...

Não tenho certeza de que a API "maximamente mínima" deva ser o objetivo do WebdriverIO (e ela já não é aplicada de forma consistente - existem ajudantes, esta não é uma estrutura apenas de blocos de construção); Eu entendo profundamente os perigos de expandir a área de superfície, mas sinto que está sendo mal aplicado aqui sobre o que acho que deveria ser um valor mais importante para esta estrutura: uma incrível experiência de desenvolvedor escrevendo testes. Ter uma API "excessiva" obviamente prejudica isso, mas também ter uma API "insuficiente" e "totalmente ruim". O fato de você ter explicado isso em um treinamento ontem deve sugerir que você flutuou muito na direção de "API muito pequena" e parece uma solução fácil.

Mesmo a palavra "reverso" na documentação da API não é ideal ... deve ser "oposto", pois "o que é o oposto de visível" é mais idiomático do que "o que é o reverso de visível".

Acho que addCommand () é considerado um recurso aceito do webdriverio neste ponto; e possivelmente ainda mais aceito no v5 do que no v4, pois toda a lógica por trás dele foi reconstruída.

@ jedwards1211 como você se sentiria em relação à terminologia chai e chamá-la de negar?

Sim, nomear talvez seja estranho: waitFor Not Exist, waitFor Not Displayed, etc. seria mais consistente, mas um inglês menos bem formado. Acho que prefiro um pouco a consistência ao invés da gramática. 🤷‍♂️

Uma abordagem funcional também pode ser uma opção:

negate($(selector).waitForExist)();
// or opposite / reverse ?

Acho que ainda seria um pouco melhor do que o booleano mágico porque a intenção é mais clara ao lê-lo, mas acho que seria um padrão desconhecido no WebdriverIO e ainda pior do que apenas $(selector).waitForNotExist() .

@abjerstedt Estou acostumado a ver Chai parecido com expect(x).not.to.be(2) , eles usam negate em qualquer lugar em sua API ou apenas nos documentos?

Eu prefiro a sugestão de @chrishyle ou me livrando de tudo menos waitUntil e deixando o usuário usar ! em sua condição waitUntil .

Ou talvez uma API do tipo chai? waitFor('foo > bar').not.to.exist ?

waitForNotExist é o mais intuitivo. Acho que muitos de nós provavelmente já tentamos ou procuramos por isso e ficamos surpresos quando não deu certo.

O que vocês acham de ter uma sintaxe como:

browser.not.waitForExist()

?

.not significa inverter o comportamento waitFor *? Vamos esperar que ainda funcione da maneira antiga?

Como uma solução temporária, os usuários que precisam desta função podem apenas definir o comando personalizado

.not significa inverter o comportamento waitFor *?

sim. Em oposição a, por exemplo, waitForNotExist ou waitForNotDisplayed

Vamos esperar que ainda funcione da maneira antiga?

O que você quer dizer?

Quero dizer, manter a capacidade de passar verdadeiro / falso como um parâmetro

Quero dizer, manter a capacidade de passar verdadeiro / falso como um parâmetro

Sim, nós manteríamos isso.

Em termos de gramática, não funciona. Precisaríamos separá-lo para ser algo como
.waitFor.not.displayed ().

@ jedwards1211 @chrishyle @MattyBalaam comenta?

ainda vamos adicionar comando?

Na v6, mudamos a estrutura desses comandos para resolver esse problema. O comando não pode ser chamado da seguinte forma:

$('body').waitForDisplayed() // waits until it is displayed
$('body').waitForDisplayed({ reverse: true }) // waits until it disappears

Espero que este seja um bom compromisso com o qual todos possam trabalhar.

ainda não é tão legível como se houvesse simplesmente um método waitForNotDisplayed , que poderia ser fornecido além de oferecer suporte a {reverse: true}

@ jedwards1211 você sempre pode adicionar um comando personalizado que adiciona esse comando ao contexto do elemento para melhor legibilidade.

Oh, tudo bem

Esta página foi útil?
0 / 5 - 0 avaliações