Commandes de requête Cypress supplémentaires pour v12 +
Ajoutez ce package en tant que dépendance de développement:
$ npm i -D cypress-map
# or using Yarn
$ yarn add -D cypress-map
Incluez ce package dans votre fichier spécifique ou support pour utiliser toutes les commandes de requête personnalisées
import 'cypress-map'
Alternative: Importez uniquement les commandes de requête dont vous avez besoin:
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 )
Cela fonctionne comme cy.then
mais cy.apply(fn)
est une commande de requête. La fonction fn
doit être synchrone, une fonction pure qui utilise uniquement l'argument du sujet et renvoie une nouvelle valeur que le rappel de fonction fn
ne peut utiliser aucune commande cypress cy
.
Vous pouvez transmettre des arguments de gauche supplémentaires à la fonction de rappel. Ensuite, il met le sujet comme dernier argument avant d'appeler la fonction:
cy . wrap ( 8 ) . apply ( Cypress . _ . subtract , 4 ) . should ( 'equal' , - 4 )
Sans arguments, cy.applyRight
fonctionne de la même manière que cy.apply
. Si vous transmettez des arguments, le sujet ainsi que les arguments deviennent les arguments du rappel. Le sujet est à la (première) position gauche
cy . wrap ( 8 ) . applyRight ( Cypress . _ . subtract , 4 ) . should ( 'equal' , 4 )
// same as
cy . wrap ( 8 )
. apply ( ( subject ) => Cypress . _ . subtract ( subject , 4 ) )
. should ( 'equal' , 4 )
Parfois, vous avez le rappel à appliquer, et vous connaissez le (s) argument (s), et vous avez juste besoin de mettre le sujet en dernière position. C'est là que vous pouvez appliquer partiellement les arguments connus au rappel donné.
// 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 )
Si le sujet actuel est un tableau ou un objet jQuery, vous pouvez appliquer le rappel donné avec des arguments au premier élément ou à l'élément. Le sujet actuel sera le dernier argument.
// cy.applyToFirst(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirst ( ( base , el ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
Si le sujet actuel est un tableau ou un objet jQuery, vous pouvez appliquer le rappel donné avec des arguments au premier élément ou à l'élément. Le sujet actuel sera le premier argument.
// cy.applyToFirstRight(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirstRight ( ( el , base ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
Nous avons souvent besoin d'appeler une méthode sur le premier élément / élément du sujet actuel
cy . get ( selector ) . invokeFirst ( 'getBoundingClientRect' )
// compute the vertical center for example
Transforme chaque objet de la collection donnée en l'exécutant via la fonction de rappel donnée. Peut également cartographier chaque objet à sa propriété. Un objet peut être un tableau ou un objet 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' ] )
Vous pouvez même cartographier les propriétés d'un objet en répertoriant les rappels. Par exemple, convertissons la propriété age
d'une chaîne en nombre
cy . wrap ( {
age : '42' ,
lucky : true ,
} )
. map ( {
age : Number ,
} )
. should ( 'deep.equal' , {
age : 42 ,
lucky : true ,
} )
Vous pouvez éviter toute conversion pour simplement choisir la liste des propriétés d'un objet
const person = {
name : 'Joe' ,
age : 21 ,
occupation : 'student' ,
}
cy . wrap ( person ) . map ( [ 'name' , 'age' ] ) . should ( 'deep.equal' , {
name : 'Joe' ,
age : 21 ,
} )
Vous pouvez extraire des chemins imbriqués en utilisant "." dans votre chemin de propriété
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
Vous pouvez fournir la valeur accumulateur initiale
cy . wrap ( [ 1 , 2 , 3 ] )
. reduce ( ( sum , n ) => sum + n , 10 )
. should ( 'equal' , 16 )
Voir réduction.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' )
AVIS: Si l'étiquette est fournie, la fonction de rappel est appelée avec l'étiquette et le sujet.
Une requête réimprimé qui appelle la fonction du constructeur donné en utilisant le new
mot-clé et le sujet actuel comme argument.
cy . wrap ( 'Jan 1, 2019' )
// same as "new Date('Jan 1, 2019')"
. make ( Date )
. invoke ( 'getFullYear' )
. should ( 'equal' , 2019 )
Un meilleur cy.log
: donne la valeur, des valeurs intelligemment stringifie en utilisant %
et une notation de format de chaîne.
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])
Voir print.cy.js pour plus d'exemples
Trouve un seul élément dans le sujet. Supposait que le sujet est un tableau ou un objet jQuery. Utilise la méthode 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' )
Voir find-one.cy.js
cy . get ( '.matching' )
. map ( 'innerText' )
. primo ( )
. invoke ( 'toUpperCase' )
. should ( 'equal' , 'FIRST' )
Voir primo.cy.js
Fonctionne comme cy.its
pour les objets, mais obtient la propriété pour les objets jQuery, ce que cy.its
ne fait pas
cy . get ( '#items li.matching' )
. last ( )
. prop ( 'ariaLabel' )
. should ( 'equal' , 'four' )
Voir prop.cy.js
Modifie une seule propriété à l'intérieur du sujet en l'exécutant via la fonction de rappel donnée. Utile pour effectuer des conversions, par exemple, convertissons la propriété "Age" en un nombre
cy . wrap ( { age : '20' } )
. update ( 'age' , Number )
. should ( 'deep.equal' , { age : 20 } )
Renvoie un élément DOM de l'objet jQuery en position k
. Renvoie un article du tableau à la position k
. Pour l'indice négatif, compte les éléments de la fin.
cy . get ( '#items li' ) . at ( - 1 ) . its ( 'innerText' ) . should ( 'equal' , 'fifth' )
Voir at.cy.js
Renvoie un élément ou un élément choisi au hasard du sujet actuel
cy . get ( '#items li' ) . sample ( ) . should ( 'have.text' , 'four' )
Si vous passez un nombre positif, il choisit plusieurs éléments ou articles
// yields jQuery object with 3 random items
cy . get ( '#items li' ) . sample ( 3 ) . should ( 'have.length' , 3 )
Voir sample.cy.js
Donne le deuxième élément du sujet actuel. Pourrait être un élément ou un élément de tableau.
cy . get ( '#items li' ) . second ( ) . should ( 'have.text' , 'second' )
Voir second.cy.js
Donne le troisième élément du sujet actuel. Pourrait être un élément ou un élément de tableau.
cy . get ( '#items li' ) . third ( ) . should ( 'have.text' , 'third' )
Voir troisième.cy.js
Enregistre le sujet actuel dans l'objet Cypress.env
. Remarque: l'objet Cypress.env est réinitialisé avant l'exécution de la spécification, mais les valeurs modifiées sont passées d'un test à l'autre. Ainsi, vous pouvez facilement passer une valeur du premier test au second.
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' )
} )
Voulez-vous vraiment faire les tests dépendants les uns des autres?
Interroge la page à l'aide de plusieurs sélecteurs et renvoie les éléments trouvés dans l'ordre spécifié , peu importe comment ils sont commandés dans le document. Retries si aucun des sélecteurs n'est trouvé.
cy . getInOrder ( 'selector1' , 'selector2' , 'selector3' , ... )
// yields a single jQuery subject with
// elements for selector1
// and selector2,
// and selector3, etc
Vous pouvez également utiliser une seule gamme de chaînes de sélecteur
cy . getInOrder ( [ 'h1' , 'h2' , 'h3' ] )
Parfois, vous voulez juste attendre que l'élément soit stable. Par exemple, si le contenu texte de l'élément ne change pas pour n millisecondes, nous pouvons considérer l'élément comme text
stable.
cy . get ( '#message' ) . stable ( 'text' )
// yields the element
Types pris en charge: text
, value
(pour les éléments d'entrée), css
et element
(compare la référence de l'élément)
Vous pouvez contrôler la période de calme (millisecondes) et passer le log
et les options timeout
// stable for 500ms
// without logging
// with maximum retries duration of 6 seconds
cy . get ( '#message' ) . stable ( 'text' , 500 , { log : false , timeout : 6_000 } )
Lorsque vous vérifiez la propriété CSS stable, fournissez le nom de la propriété:
// 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)' )
Voir stable.cy.js et stable-css.cy.js
expérimental
RETOURS jusqu'à ce que l'élément avec le sélecteur donné se détache de DOM.
cy . contains ( 'Click to re-render' ) . click ( )
cy . detaches ( '#list' )
Parfois, le détachement peut se produire correctement avec l'action et les cy.detaches(selector)
sont trop tard . Si vous savez que le détachement a peut-être déjà eu lieu, vous devez vous y préparer en utilisant un alias stocké dans l'objet Cypress.env
:
cy . get ( '#name2' ) . asEnv ( 'name' )
cy . contains ( 'Click to remove Joe' ) . click ( )
cy . detaches ( '@name' )
L'objet jQuery sera stocké à l'intérieur du Cypress.env
sous la propriété name
.
Voir détach.cy.js
Calcule un objet / tableaux de la différence avec l'objet / tableau de sujet actuel.
cy . wrap ( { name : 'Joe' , age : 20 } )
. difference ( { name : 'Joe' , age : 30 } )
. should ( 'deep.equal' , { age : { actual : 20 , expected : 30 } } )
Vous pouvez utiliser des fonctions de prédicat synchrone pour valider les propriétés
// confirm the value of the "age" property
// is larger than 15
. difference ( { name : 'Joe' , age : ( n ) => n > 15 } )
Rapporte des propriétés manquantes et supplémentaires. Voir différence.cy.js
Remarque: Utilisez have.length
pour valider le nombre d'éléments dans un tableau:
// 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 )
Vous pouvez vérifier chaque élément du sujet du tableau à l'aide de valeurs / prédicats de l'objet attendu.
// list of people objects
cy . wrap ( people )
. difference ( {
name : Cypress . _ . isString ,
age : ( age ) => age > 1 && age < 100 ,
} )
. should ( 'be.empty' )
Pour en savoir plus sur la commande cy.table
, lisez le blog Tester les tables HTML à l'aide de la commande de requête CY.Table.
Extrait toutes les cellules du tableau des sujets actuels. Donne un tableau 2D de chaînes.
cy . get ( 'table' ) . table ( )
Vous pouvez trancher la table pour céder une région .table(x, y, w, h)
Par exemple, vous pouvez obtenir 2 par sous-région par 2
cy . get ( 'table' )
. table ( 0 , 2 , 2 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
Voir la table de spécification.cy.js pour plus d'exemples.
Astuce: vous pouvez combiner cy.table
avec cy.map
, cy.mapInvoke
pour obtenir les parties de la table. Par exemple, la même partie 2x2 du tableau pourrait être extraite avec:
cy . get ( 'table' )
. table ( )
. invoke ( 'slice' , 2 , 4 )
. mapInvoke ( 'slice' , 0 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
Astuce 2: Pour obtenir uniquement la ligne des en-têtes, combinez .table
et .its
cy . get ( 'table' )
. table ( 0 , 0 , 3 , 1 )
. its ( 0 )
. should ( 'deep.equal' , [ 'Name' , 'Age' , 'Date (YYYY-MM-DD)' ] )
Pour obtenir la dernière rangée, vous pourriez faire:
cy . get ( 'table' ) . table ( ) . invoke ( 'slice' , - 1 ) . its ( 0 )
Pour obtenir la première colonne jointe dans un seul tableau (au lieu de la table de baies 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' ] )
Une requête pour convertir des objets DOM spéciaux en objets simples. Par exemple, pour convertir l'instance DOMStringMap
en un objet simple compatible avec une affirmation deep.equal
cy . get ( 'article' )
. should ( 'have.prop' , 'dataset' )
. toPlainObject ( )
. should ( 'deep.equal' , {
columns : '3' ,
indexNumber : '12314' ,
parent : 'cars' ,
} )
Par défaut, utilise JSON Stringify et analyse le dos. Si vous souhaitez convertir à l'aide entries
et fromEntries
, ajoutez un argument:
cy . wrap ( new URLSearchParams ( searchParams ) ) . toPlainObject ( 'entries' )
Dans Cypress V12 cy.invoke
est devenu une requête, qui a fait du travail avec des méthodes asynchrones vraiment lourdes. Le cy.invokeOnce
est un retour l'ancienne façon d'appeler la méthode et de donner la valeur résolue.
cy . wrap ( app )
// app.fetchName is an asynchronous method
// that returns a Promise
. invokeOnce ( 'fetchName' )
. should ( 'equal' , 'My App' )
Voir la spécification invoke-once.cy.js pour plus d'exemples.
Voici quelques exemples pour clarifier les différents entre les commandes de requête cy.invoke
, cy.map
et cy.mapInvoke
, voir 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 ] )
J'ai ajouté une autre commande utile (pas une requête!) À ce package. Il vous permet de traiter les éléments dans le sujet du tableau un par un via des fonctions de commande synchrones, asynchrones ou cy
. En cy.each
// 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 => ... )
Ce package comprend des définitions de commandes TypeScript pour ses commandes personnalisées dans les commandes de fichiers / index.d.ts. Pour l'utiliser à partir de vos spécifications JavaScript:
/// <reference types="cypress-map" />
Si vous utilisez TypeScript, incluez ce module dans votre liste de types
{
"compilerOptions" : {
"types" : [ " cypress " , " cypress-map " ]
}
}
Le code source se trouve dans le dossier SRC / Commandes. La commande build produit du code ES5 qui va dans le dossier commands
(ne doit pas être vérifié dans le contrôle du code source). Le package.json
dans sa distribution NPM comprend commands
ainsi que les types du fichier src/commands/index.d.ts
.
should(callback)
à la volée. Remarque: Ce module n'a pas de méthode filter
car Cypress API a des commandes de requête CY.filter et cy.invoke que vous pouvez utiliser pour filtrer les éléments dans un objet JQuery ou des éléments dans un tableau. Voir les exemples de la spécification filtre.cy.js. Voir les éléments du filtre vidéo et les éléments avec des tentatives.
Auteur: Gleb Bahmutov <[email protected]> © 2022
Licence: MIT - Faites quoi que ce soit avec le code, mais ne me blâmez pas si cela ne fonctionne pas.
Prise en charge: si vous trouvez des problèmes avec ce module, envoyez un e-mail / tweet / ouvert sur GitHub