Comandos extras de consulta do Cypress para V12+
Adicione este pacote como uma dependência de desenvolvimento:
$ npm i -D cypress-map
# or using Yarn
$ yarn add -D cypress-map
Inclua este pacote em seu arquivo específico ou suporte para usar todos os comandos de consulta personalizados
import 'cypress-map'
Alternativa: importar apenas os comandos de consulta que você precisa:
import 'cypress-map/commands/map'
import 'cypress-map/commands/tap'
// and so on, see the /commands folder
const double = ( n ) => n * 2
cy . wrap ( 100 ) . apply ( double ) . should ( 'equal' , 200 )
Funciona como cy.then
, mas cy.apply(fn)
é um comando de consulta. A função fn
deve ser síncrona, função pura que usa apenas o argumento do sujeito e retorna novo valor O retorno de chamada da função fn
não pode usar nenhum comandos do Cypress cy
.
Você pode passar argumentos de esquerda adicionais para a função de retorno de chamada. Então ele coloca o assunto como último argumento antes de chamar a função:
cy . wrap ( 8 ) . apply ( Cypress . _ . subtract , 4 ) . should ( 'equal' , - 4 )
Sem argumentos, cy.applyRight
funciona da mesma forma que cy.apply
. Se você passar argumentos, o assunto mais os argumentos se tornarão os argumentos para o retorno de chamada. O assunto está à esquerda (primeiro) posição
cy . wrap ( 8 ) . applyRight ( Cypress . _ . subtract , 4 ) . should ( 'equal' , 4 )
// same as
cy . wrap ( 8 )
. apply ( ( subject ) => Cypress . _ . subtract ( subject , 4 ) )
. should ( 'equal' , 4 )
Às vezes, você tem o retorno de chamada para se inscrever e conhece os primeiros argumentos e só precisa colocar o assunto na última posição. É aqui que você pode aplicar parcialmente os argumentos conhecidos ao retorno de chamada fornecido.
// the Cypress._.add takes to arguments (a, b)
// we know the first argument a = 5
// so we partially apply it and wait for the subject = b argument
cy . wrap ( 100 ) . partial ( Cypress . _ . add , 5 ) . should ( 'equal' , 105 )
// same as
cy . wrap ( 100 )
. apply ( ( subject ) => Cypress . _ . add ( 5 , subject ) )
. should ( 'equal' , 105 )
Se o assunto atual for uma matriz ou um objeto jQuery, você poderá aplicar o retorno de chamada fornecido com argumentos ao primeiro item ou elemento. O assunto atual será o último argumento.
// cy.applyToFirst(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirst ( ( base , el ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
Se o assunto atual for uma matriz ou um objeto jQuery, você poderá aplicar o retorno de chamada fornecido com argumentos ao primeiro item ou elemento. O assunto atual será o primeiro argumento.
// cy.applyToFirstRight(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirstRight ( ( el , base ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
Muitas vezes, precisamos chamar um método no primeiro elemento / item no assunto atual
cy . get ( selector ) . invokeFirst ( 'getBoundingClientRect' )
// compute the vertical center for example
Transforma todos os objetos da coleção dada, executando -o através da função de retorno de chamada fornecida. Também pode mapear cada objeto para sua propriedade. Um objeto pode ser uma matriz ou um objeto jQuery.
// map elements by invoking a function
cy . wrap ( [ '10' , '20' , '30' ] ) . map ( Number ) // [10, 20, 30]
// map elements by a property
cy . get ( '.matching' )
. map ( 'innerText' )
. should ( 'deep.equal' , [ 'first' , 'third' , 'fourth' ] )
Você pode até mapear as propriedades de um objeto listando retornos de chamada. Por exemplo, vamos converter a propriedade age
de uma string para um número
cy . wrap ( {
age : '42' ,
lucky : true ,
} )
. map ( {
age : Number ,
} )
. should ( 'deep.equal' , {
age : 42 ,
lucky : true ,
} )
Você pode evitar qualquer conversão para simplesmente escolher a lista de propriedades de um objeto
const person = {
name : 'Joe' ,
age : 21 ,
occupation : 'student' ,
}
cy . wrap ( person ) . map ( [ 'name' , 'age' ] ) . should ( 'deep.equal' , {
name : 'Joe' ,
age : 21 ,
} )
Você pode extrair caminhos aninhados usando "". no caminho da sua propriedade
cy . wrap ( people )
. map ( 'name.first' )
. should ( 'deep.equal' , [ 'Joe' , 'Anna' ] )
// equivalent to
cy . wrap ( people )
. map ( 'name' )
. map ( 'first' )
. should ( 'deep.equal' , [ 'Joe' , 'Anna' ] )
cy . get ( '#items li' )
. find ( '.price' )
. map ( 'innerText' )
. mapInvoke ( 'replace' , '$' , '' )
. mapInvoke ( 'trim' )
cy . get ( '#items li' )
. find ( '.price' )
. map ( 'innerText' )
. mapInvoke ( 'replace' , '$' , '' )
. map ( parseFloat )
. reduce ( ( max , n ) => ( n > max ? n : max ) )
// yields the highest price
Você pode fornecer o valor do acumulador inicial
cy . wrap ( [ 1 , 2 , 3 ] )
. reduce ( ( sum , n ) => sum + n , 10 )
. should ( 'equal' , 16 )
Consulte Reduce.cy.js
cy . get ( '#items li' )
. find ( '.price' )
. map ( 'innerText' )
. tap ( ) // console.log by default
. mapInvoke ( 'replace' , '$' , '' )
. mapInvoke ( 'trim' )
// console.info with extra label
. tap ( console . info , 'trimmed strings' )
Aviso: Se o rótulo for fornecido, a função de retorno de chamada será chamada com o rótulo e o assunto.
Uma consulta de repetível que chama a função do construtor fornecido usando a new
palavra -chave e o assunto atual como argumento.
cy . wrap ( 'Jan 1, 2019' )
// same as "new Date('Jan 1, 2019')"
. make ( Date )
. invoke ( 'getFullYear' )
. should ( 'equal' , 2019 )
Um cy.log
melhor: produz o valor, rigem de forma inteligente valores usando a notação %
e formato de string.
cy . wrap ( 42 )
. print ( ) // "42"
// and yields the value
. should ( 'equal' , 42 )
// pass formatting string
cy . wrap ( 42 ) . print ( 'the answer is %d' ) // "the answer is 42"
cy . wrap ( { name : 'Joe' } ) . print ( 'person %o' ) // 'person {"name":"Joe"}'
// use {0} with dot notation, supported deep properties
// https://github.com/davidchambers/string-format
cy . wrap ( { name : 'Joe' } ) . print ( 'person name {0.name}' ) // "person name Joe"
// print the length of an array
cy . wrap ( arr ) . print ( 'array length {0.length}' ) // "array length ..."
// pass your own function to return formatted string
cy . wrap ( arr ) . print ( ( a ) => `array with ${ a . length } items` )
// if you return a non-string, it will attempt to JSON.stringify it
cy . wrap ( arr ) . print ( ( list ) => list [ 2 ] ) // JSON.stringify(arr[2])
Veja print.cy.js para mais exemplos
Encontra um único item no assunto. Supõe que o assunto seja uma matriz ou um objeto jQuery. Usa o método lodash _.find
.
// using predicate function
const isThree = n => n === 3
cy . wrap ( [ ... ] ) . findOne ( isThree ) . should ( 'equal' , 3 )
// using partial known properties of an object
cy . wrap ( [ ... ] ) . findOne ( { name : 'Anna' } ) . should ( 'have.property' , 'name' , 'Anna' )
Veja find-one.cy.js
cy . get ( '.matching' )
. map ( 'innerText' )
. primo ( )
. invoke ( 'toUpperCase' )
. should ( 'equal' , 'FIRST' )
Veja Primo.cy.js
Funciona como cy.its
para objetos, mas recebe a propriedade para objetos jQuery, que cy.its
não
cy . get ( '#items li.matching' )
. last ( )
. prop ( 'ariaLabel' )
. should ( 'equal' , 'four' )
Veja Prop.cy.js
Altera uma única propriedade dentro do assunto executando -a através da função de retorno de chamada fornecida. Útil para digitar conversões, por exemplo, vamos converter a propriedade "idade" em um número
cy . wrap ( { age : '20' } )
. update ( 'age' , Number )
. should ( 'deep.equal' , { age : 20 } )
Retorna um elemento DOM do objeto jQuery na posição k
. Retorna um item da matriz na posição k
. Para índice negativo, conta os itens do final.
cy . get ( '#items li' ) . at ( - 1 ) . its ( 'innerText' ) . should ( 'equal' , 'fifth' )
Veja at.cy.js
Retorna um item ou elemento escolhido aleatoriamente do assunto atual
cy . get ( '#items li' ) . sample ( ) . should ( 'have.text' , 'four' )
Se você passar um número positivo, ele escolhe vários elementos ou itens
// yields jQuery object with 3 random items
cy . get ( '#items li' ) . sample ( 3 ) . should ( 'have.length' , 3 )
Veja Sample.cy.js
Produz o segundo elemento do assunto atual. Pode ser um elemento ou um item de matriz.
cy . get ( '#items li' ) . second ( ) . should ( 'have.text' , 'second' )
Veja Second.cy.js
Produz o terceiro elemento do assunto atual. Pode ser um elemento ou um item de matriz.
cy . get ( '#items li' ) . third ( ) . should ( 'have.text' , 'third' )
Veja terceiro.cy.js
Salva o assunto atual no objeto Cypress.env
. NOTA: O objeto Cypress.env é redefinido antes da execução da especificação, mas os valores alterados são passados de teste para teste. Assim, você pode passar facilmente um valor do primeiro teste para o segundo.
it ( 'saves value in this test' , ( ) => {
cy . wrap ( 'hello, world' ) . asEnv ( 'greeting' )
} )
it ( 'saved value is available in this test' , ( ) => {
expect ( Cypress . env ( 'greeting' ) , 'greeting' ) . to . equal ( 'hello, world' )
} )
Você realmente quer tornar os testes dependentes um do outro?
Consulta a página usando vários seletores e retorna os elementos encontrados na ordem especificada , não importa como eles sejam encomendados no documento. EXPETIRAS se algum dos seletores não for encontrado.
cy . getInOrder ( 'selector1' , 'selector2' , 'selector3' , ... )
// yields a single jQuery subject with
// elements for selector1
// and selector2,
// and selector3, etc
Você também pode usar uma única variedade de strings de seletor
cy . getInOrder ( [ 'h1' , 'h2' , 'h3' ] )
Às vezes você só quer esperar até que o elemento esteja estável. Por exemplo, se o conteúdo de texto do elemento não mudar para n milissegundos, podemos considerar o elemento estável em text
.
cy . get ( '#message' ) . stable ( 'text' )
// yields the element
Tipos suportados: text
, value
(para elementos de entrada), css
e element
(compara a referência do elemento)
Você pode controlar o período tranquilo (milissegundos) e passar o log
e as opções de timeout
// stable for 500ms
// without logging
// with maximum retries duration of 6 seconds
cy . get ( '#message' ) . stable ( 'text' , 500 , { log : false , timeout : 6_000 } )
Ao verificar a propriedade CSS para ser estável, forneça o nome da propriedade:
// retries until the CSS animation finishes
// and the background color is red
cy . get ( '#message' )
. stable ( 'css' , 'background-color' , 100 )
// yields the element
. should ( 'have.css' , 'background-color' , 'rgb(255, 0, 0)' )
Veja stable.cy.js e stable-css.cy.js
experimental
EXPERIR A até que o elemento com o seletor fornecido se afasta de DOM.
cy . contains ( 'Click to re-render' ) . click ( )
cy . detaches ( '#list' )
Às vezes, o desapego pode acontecer com a ação e os cy.detaches(selector)
são tarde demais . Se você sabe que o desapego pode já ter acontecido, precisa se preparar para ele usando um alias armazenado no objeto Cypress.env
:
cy . get ( '#name2' ) . asEnv ( 'name' )
cy . contains ( 'Click to remove Joe' ) . click ( )
cy . detaches ( '@name' )
O objeto jQuery será armazenado dentro do Cypress.env
sob a propriedade name
.
Veja Detsach.cy.js
Calcula um objeto/matrizes da diferença com o objeto/matriz atual.
cy . wrap ( { name : 'Joe' , age : 20 } )
. difference ( { name : 'Joe' , age : 30 } )
. should ( 'deep.equal' , { age : { actual : 20 , expected : 30 } } )
Você pode usar funções de predicado síncrono para validar propriedades
// confirm the value of the "age" property
// is larger than 15
. difference ( { name : 'Joe' , age : ( n ) => n > 15 } )
Relatórios ausentes e propriedades extras. Veja diferença.cy.js
NOTA: Use have.length
para validar o número de itens em uma matriz:
// let's check if there are 3 objects in the array
// INSTEAD OF THIS
. difference ( [ Cypress . _ . object , Cypress . _ . object , Cypress . _ . object ] )
// USE AN ASSERTION
. should ( 'have.length' , 3 )
Você pode verificar cada item no assunto da matriz usando valores / predicados do objeto esperado.
// list of people objects
cy . wrap ( people )
. difference ( {
name : Cypress . _ . isString ,
age : ( age ) => age > 1 && age < 100 ,
} )
. should ( 'be.empty' )
Para saber mais sobre o comando cy.table
, leia as tabelas HTML de teste de blog usando o comando cy.table Query.
Extrai todas as células da tabela de assunto atual. Produz uma variedade 2D de cordas.
cy . get ( 'table' ) . table ( )
Você pode cortar a tabela para produzir apenas uma região .table(x, y, w, h)
Por exemplo, você pode obter 2 por 2 sub -região
cy . get ( 'table' )
. table ( 0 , 2 , 2 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
Consulte a tabela de especificações.cy.js para mais exemplos.
Dica: você pode combinar cy.table
com cy.map
, cy.mapInvoke
para obter as partes da tabela. Por exemplo, a mesma parte 2x2 da tabela pode ser extraída com:
cy . get ( 'table' )
. table ( )
. invoke ( 'slice' , 2 , 4 )
. mapInvoke ( 'slice' , 0 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
Dica 2: Para obter apenas a linha dos títulos, combine .table
e .its
consultas
cy . get ( 'table' )
. table ( 0 , 0 , 3 , 1 )
. its ( 0 )
. should ( 'deep.equal' , [ 'Name' , 'Age' , 'Date (YYYY-MM-DD)' ] )
Para obter a última fila, você pode fazer:
cy . get ( 'table' ) . table ( ) . invoke ( 'slice' , - 1 ) . its ( 0 )
Para obter a primeira coluna unida a uma única matriz (em vez de matriz de matrizes 1x1)
cy . get ( 'table' )
. table ( 0 , 1 , 1 ) // skip the heading "Name" cell
// combine 1x1 arrays into one array
. invoke ( 'flatMap' , Cypress . _ . identity )
. should ( 'deep.equal' , [ 'Dave' , 'Cary' , 'Joe' , 'Anna' ] )
Uma consulta para converter objetos DOM especiais em objetos simples. Por exemplo, para converter a instância DOMStringMap
em um objeto simples compatível com a afirmação deep.equal
cy . get ( 'article' )
. should ( 'have.prop' , 'dataset' )
. toPlainObject ( )
. should ( 'deep.equal' , {
columns : '3' ,
indexNumber : '12314' ,
parent : 'cars' ,
} )
Por padrão, usa o JSON Stringify e o Recond Back. Se você deseja converter usando entries
e fromEntries
, adicione um argumento:
cy . wrap ( new URLSearchParams ( searchParams ) ) . toPlainObject ( 'entries' )
No Cypress V12, cy.invoke
se tornou uma consulta, o que tornou o trabalho com métodos assíncronos realmente pesados. O cy.invokeOnce
é um retorno da maneira antiga de chamar o método e produzir o valor resolvido.
cy . wrap ( app )
// app.fetchName is an asynchronous method
// that returns a Promise
. invokeOnce ( 'fetchName' )
. should ( 'equal' , 'My App' )
Consulte o SPEC Invoke-once.cy.js para obter mais exemplos.
Aqui estão alguns exemplos para esclarecer os diferentes comandos cy.invoke
, cy.map
e cy.mapInvoke
, consulte Diff.cy.js
const list = [ 'apples' , 'plums' , 'bananas' ]
// cy.invoke
cy . wrap ( list )
// calls ".sort()" on the list
. invoke ( 'sort' )
. should ( 'deep.equal' , [ 'apples' , 'bananas' , 'plums' ] )
// cy.mapInvoke
cy . wrap ( list )
// calls ".toUpperCase()" on every string in the list
. mapInvoke ( 'toUpperCase' )
. should ( 'deep.equal' , [ 'APPLES' , 'PLUMS' , 'BANANAS' ] )
// cy.map
const reverse = ( s ) => s . split ( '' ) . reverse ( ) . join ( '' )
cy . wrap ( list )
// reverses each string in the list
. map ( reverse )
. should ( 'deep.equal' , [ 'selppa' , 'smulp' , 'sananab' ] )
// grabs the "length" property from each string
. map ( 'length' )
. should ( 'deep.equal' , [ 6 , 5 , 7 ] )
Eu adicionei outro comando útil (não uma consulta!) A este pacote. Ele permite que você processe itens no assunto da matriz um por um por meio de funções de comando síncronas, assíncronas ou cy
. Isso ocorre porque a solução comum para buscar itens usando cy.each
, por exemplo, não funciona:
// fetch the users from a list of ids
// DOES NOT WORK
cy . get ( ids ) . each ( id => cy . request ( '/users/' + id ) ) . then ( users => ... )
// Nope, the yielded "users" result is ... still the "ids" subject
// ✅ CORRECT SOLUTION
cy . get ( ids ) . mapChain ( id => cy . request ( '/users/' + id ) ) . then ( users => ... )
Este pacote inclui as definições de comando TypeScript para seus comandos personalizados nos comandos do arquivo/index.d.ts. Para usá -lo nas especificações do JavaScript:
/// <reference types="cypress-map" />
Se você estiver usando o TypeScript, inclua este módulo em sua lista de tipos
{
"compilerOptions" : {
"types" : [ " cypress " , " cypress-map " ]
}
}
O código -fonte está na pasta SRC/Commands. O comando Build produz código ES5 que entra na pasta de commands
(não deve ser verificado no controle do código -fonte). O package.json
em sua distribuição NPM inclui commands
mais os tipos do arquivo src/commands/index.d.ts
.
should(callback)
em tempo real. Nota: Este módulo não possui método filter
porque a API do Cypress possui comandos de consulta cy.filter e cy.invoke que você pode usar para filtrar elementos em um objeto ou itens jQuery em uma matriz. Veja os exemplos no filtro.cy.js spec. Consulte elementos de filtro de vídeo e itens com tentativas.
Autor: Gleb bahmutov <[email protected]> © 2022
Licença: MIT - faça qualquer coisa com o código, mas não me culpe se não funcionar.
Suporte: se você encontrar algum problema com este módulo, email / tweet / edição aberta no github