V12+的額外柏樹查詢命令
將此軟件包添加為DEV依賴性:
$ npm i -D cypress-map
# or using Yarn
$ yarn add -D cypress-map
在您的規格或支持文件中包含此軟件包,以使用所有自定義查詢命令
import 'cypress-map'
替代:僅導入您需要的查詢命令:
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 )
它的工作方式像cy.then
cy.apply(fn)
函數fn
應該是同步的,純函數,僅使用主題參數並返回新值函數回調fn
不能使用任何柏樹命令cy
。
您可以將其他左參數傳遞給回調函數。然後,它在調用函數之前將主題作為最後一個參數:
cy . wrap ( 8 ) . apply ( Cypress . _ . subtract , 4 ) . should ( 'equal' , - 4 )
沒有爭論, cy.applyRight
工作方式與cy.apply
相同。如果您通過參數,則主題加上參數將成為回調的論點。主題在左側(第一個)位置
cy . wrap ( 8 ) . applyRight ( Cypress . _ . subtract , 4 ) . should ( 'equal' , 4 )
// same as
cy . wrap ( 8 )
. apply ( ( subject ) => Cypress . _ . subtract ( subject , 4 ) )
. should ( 'equal' , 4 )
有時,您需要申請回調,並且您知道第一個參數,只需要將主題放在最後一個位置即可。在這裡,您可以將已知參數部分應用於給定的回調。
// 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 )
如果當前主題是數組或jQuery對象,則可以將帶有參數的給定回調應用於第一個項目或元素。當前的主題將是最後一個論點。
// cy.applyToFirst(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirst ( ( base , el ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
如果當前主題是數組或jQuery對象,則可以將帶有參數的給定回調應用於第一個項目或元素。當前的主題將是第一個參數。
// cy.applyToFirstRight(callback, ...args)
cy . wrap ( Cypress . $ ( '<div>100</div><div>200</div>' ) )
. applyToFirstRight ( ( el , base ) => parseInt ( el . innerText , base ) , 10 )
. should ( 'equal' , 100 )
我們通常只需要在當前主題中的第一個元素 /項目上調用方法
cy . get ( selector ) . invokeFirst ( 'getBoundingClientRect' )
// compute the vertical center for example
通過通過給定的回調函數運行給定集合中的每個對象。還可以將每個對象映射到其屬性。對象可以是數組或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' ] )
您甚至可以通過列出回調來映射對象的屬性。例如,讓我們將age
屬性從字符串轉換為數字
cy . wrap ( {
age : '42' ,
lucky : true ,
} )
. map ( {
age : Number ,
} )
. should ( 'deep.equal' , {
age : 42 ,
lucky : true ,
} )
您可以避免任何轉換以簡單地從對像中選擇屬性列表
const person = {
name : 'Joe' ,
age : 21 ,
occupation : 'student' ,
}
cy . wrap ( person ) . map ( [ 'name' , 'age' ] ) . should ( 'deep.equal' , {
name : 'Joe' ,
age : 21 ,
} )
您可以使用“”提取嵌套路徑。在您的財產路徑中
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
您可以提供初始累加器值
cy . wrap ( [ 1 , 2 , 3 ] )
. reduce ( ( sum , n ) => sum + n , 10 )
. should ( 'equal' , 16 )
請參閱deled.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' )
注意:如果提供了標籤,則使用標籤和主題調用回調功能。
一個可用的查詢,該查詢使用new
關鍵字和當前主題為參數調用給定的構造函數函數。
cy . wrap ( 'Jan 1, 2019' )
// same as "new Date('Jan 1, 2019')"
. make ( Date )
. invoke ( 'getFullYear' )
. should ( 'equal' , 2019 )
更好的cy.log
:產生值,使用%
和字符串格式符號智能地串制值。
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])
有關更多示例,請參見print.cy.js
在主題中找到一個項目。假設主題是數組或jQuery對象。使用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' )
請參閱Find-One.cy.js
cy . get ( '.matching' )
. map ( 'innerText' )
. primo ( )
. invoke ( 'toUpperCase' )
. should ( 'equal' , 'FIRST' )
參見Primo.cy.js
像cy.its
的對像一樣工作,但獲取jQuery對象的屬性,而cy.its
卻沒有
cy . get ( '#items li.matching' )
. last ( )
. prop ( 'ariaLabel' )
. should ( 'equal' , 'four' )
請參閱Prop.cy.js
通過給定回調功能運行主題內部的單個屬性。例如,對類型轉換有用,例如,讓我們將“年齡”屬性轉換為一個數字
cy . wrap ( { age : '20' } )
. update ( 'age' , Number )
. should ( 'deep.equal' , { age : 20 } )
從位置k
處返回jQuery對象的DOM元素。從位置k
陣列返回一個項目。對於負索引,從最後計數項目。
cy . get ( '#items li' ) . at ( - 1 ) . its ( 'innerText' ) . should ( 'equal' , 'fifth' )
請參閱at.cy.js
從當前主題返回隨機選擇的項目或元素
cy . get ( '#items li' ) . sample ( ) . should ( 'have.text' , 'four' )
如果您通過一個正數,則選擇多個元素或項目
// yields jQuery object with 3 random items
cy . get ( '#items li' ) . sample ( 3 ) . should ( 'have.length' , 3 )
參見sample.cy.js
從當前主題中產生第二個元素。可能是元素或數組項目。
cy . get ( '#items li' ) . second ( ) . should ( 'have.text' , 'second' )
請參閱second.cy.js
從當前主題中產生第三個元素。可能是元素或數組項目。
cy . get ( '#items li' ) . third ( ) . should ( 'have.text' , 'third' )
請參閱第三
將當前主題保存在Cypress.env
對像中。注意:cypress.env對像是在規格運行之前重置的,但是更改值從測試到測試傳遞。因此,您可以輕鬆地將值從第一個測試傳遞到第二個測試。
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' )
} )
您是否真的想進行測試彼此取決於彼此?
使用多個選擇器查詢頁面,並以指定順序返回所找到的元素,無論它們在文檔中如何訂購。如果找不到任何選擇器,請重試。
cy . getInOrder ( 'selector1' , 'selector2' , 'selector3' , ... )
// yields a single jQuery subject with
// elements for selector1
// and selector2,
// and selector3, etc
您也可以使用單個選擇器字符串
cy . getInOrder ( [ 'h1' , 'h2' , 'h3' ] )
有時您只想等到元素穩定。例如,如果元素的文本內容沒有變化,則可以將元素視為text
穩定的元素。
cy . get ( '#message' ) . stable ( 'text' )
// yields the element
支持類型: text
, value
(對於輸入元素), css
和element
(比較元素參考)
您可以控制安靜的時期(毫秒),並傳遞log
和timeout
選項
// stable for 500ms
// without logging
// with maximum retries duration of 6 seconds
cy . get ( '#message' ) . stable ( 'text' , 500 , { log : false , timeout : 6_000 } )
在檢查CSS屬性穩定時,請提供該屬性的名稱:
// 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)' )
請參閱stable.cy.js和stable-css.cy.js
實驗
重試直到給定選擇器從DOM脫離的元件。
cy . contains ( 'Click to re-render' ) . click ( )
cy . detaches ( '#list' )
有時,分離可能會隨著動作而發生,而cy.detaches(selector)
為時已晚。如果您知道分離已經發生了,則需要使用存儲在Cypress.env
對像中的別名來準備它:
cy . get ( '#name2' ) . asEnv ( 'name' )
cy . contains ( 'Click to remove Joe' ) . click ( )
cy . detaches ( '@name' )
jQuery對象將以name
屬性存儲在Cypress.env
中。
請參閱distach.cy.js
計算與當前主題對象/數組的差異對象/數組。
cy . wrap ( { name : 'Joe' , age : 20 } )
. difference ( { name : 'Joe' , age : 30 } )
. should ( 'deep.equal' , { age : { actual : 20 , expected : 30 } } )
您可以使用同步謂詞函數來驗證屬性
// confirm the value of the "age" property
// is larger than 15
. difference ( { name : 'Joe' , age : ( n ) => n > 15 } )
報告缺失和額外的屬性。參見差異。cy.js
注意:使用have.length
驗證數組中的項目數:
// 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 )
您可以使用預期對象的值 /謂詞在數組主題中檢查每個項目。
// list of people objects
cy . wrap ( people )
. difference ( {
name : Cypress . _ . isString ,
age : ( age ) => age > 1 && age < 100 ,
} )
. should ( 'be.empty' )
要了解有關cy.table
命令的更多信息,請使用cy.table查詢命令閱讀博客文章測試HTML表。
從當前主題表中提取所有細胞。產生一個2D的字符串。
cy . get ( 'table' ) . table ( )
您可以將桌子切成薄片以產生一個區域.table(x, y, w, h)
例如,您可以獲得2乘2個子區域
cy . get ( 'table' )
. table ( 0 , 2 , 2 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
有關更多示例,請參見Spec Table.cy.js。
提示:您可以將cy.table
與cy.map
, cy.mapInvoke
結合在一起,以獲取桌子的各個部分。例如,可以提取表的相同2x2部分:
cy . get ( 'table' )
. table ( )
. invoke ( 'slice' , 2 , 4 )
. mapInvoke ( 'slice' , 0 , 2 )
. should ( 'deep.equal' , [
[ 'Cary' , '30' ] ,
[ 'Joe' , '28' ] ,
] )
提示2:要僅獲取標題行,請組合.table
表並查詢.its
cy . get ( 'table' )
. table ( 0 , 0 , 3 , 1 )
. its ( 0 )
. should ( 'deep.equal' , [ 'Name' , 'Age' , 'Date (YYYY-MM-DD)' ] )
要獲得最後一行,您可以做:
cy . get ( 'table' ) . table ( ) . invoke ( 'slice' , - 1 ) . its ( 0 )
要使第一列連接到一個數組中(而不是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' ] )
查詢將特殊的DOM對象轉換為普通對象。例如,將DOMStringMap
實例轉換為與deep.equal
兼容的普通對象。
cy . get ( 'article' )
. should ( 'have.prop' , 'dataset' )
. toPlainObject ( )
. should ( 'deep.equal' , {
columns : '3' ,
indexNumber : '12314' ,
parent : 'cars' ,
} )
默認情況下,使用JSON Stringify並解析。如果要使用entries
和fromEntries
轉換,請添加一個參數:
cy . wrap ( new URLSearchParams ( searchParams ) ) . toPlainObject ( 'entries' )
在柏樹v12 cy.invoke
中成為一個查詢,這使得使用異步方法的工作真的很笨拙。 cy.invokeOnce
是返回呼叫該方法並產生解決值的舊方式。
cy . wrap ( app )
// app.fetchName is an asynchronous method
// that returns a Promise
. invokeOnce ( 'fetchName' )
. should ( 'equal' , 'My App' )
有關更多示例,請參見Spec Invoke-once.cy.js。
以下是一些示例,可以闡明cy.invoke
, cy.map
和cy.mapInvoke
查詢命令之間的不同之處,請參見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 ] )
我在此軟件包中添加了另一個有用的命令(不是查詢!)。它允許您通過同步,異步或CY命令函數通過同步,異步或cy
命令函數在數組中的主題中處理項目。這是因為使用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 => ... )
此軟件包在文件命令/index.d.ts中包含其自定義命令的打字稿命令定義。從JavaScript規格中使用它:
/// <reference types="cypress-map" />
如果您使用的是打字稿,請在類型列表中包含此模塊
{
"compilerOptions" : {
"types" : [ " cypress " , " cypress-map " ]
}
}
源代碼在SRC/命令文件夾中。構建命令生成commands
文件夾中的ES5代碼(不應將其檢查到源代碼控制中)。 npm發行版中的package.json
包括commands
以及src/commands/index.d.ts
文件中的類型。
should(callback)
功能。注意:此模塊沒有filter
方法,因為Cypress API具有查詢命令Cy.Filter和Cy.invoke,您可以用來過濾jQuery對像中的元素或數組中的項目。請參閱filter.cy.js規格中的示例。請參閱帶有重試的視頻過濾器元素和項目。
作者:gleb bahmutov <[email protected]>©2022
許可證:麻省理工學院 - 對代碼做任何事情,但是如果它不起作用,請不要怪我。
支持:如果您發現此模塊有任何問題,請在GitHub上發送電子郵件 /推文 /打開問題