أوامر استعلام Cypress إضافية لـ 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
استخدام أي أوامر Cypress 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 )
انظر تخفيض. سي. ج
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.cs
يغير خاصية واحدة داخل الموضوع عن طريق تشغيله من خلال وظيفة رد الاتصال المحددة. من المفيد إجراء تحويلات النوع ، على سبيل المثال ، دعنا نحول خاصية "العمر" إلى رقم
cy . wrap ( { age : '20' } )
. update ( 'age' , Number )
. should ( 'deep.equal' , { age : 20 } )
إرجاع عنصر DOM من كائن jQuery في الموضع k
إرجاع عنصر من صفيف في الموضع 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' ] )
في بعض الأحيان تريد فقط الانتظار حتى يصبح العنصر مستقرًا. على سبيل المثال ، إذا لم يتغير محتوى النص للعنصر بالنسبة إلى N -milliseconds ، فيمكننا أن نعتبر العنصر 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)' )
انظر مستقر.
تجريبي
يحفظ حتى ينفصل العنصر مع المحدد المعطى من 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 داخل Cypress.env
ضمن خاصية name
.
انظر detach.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 } )
تقارير مفقودة وخصائص إضافية. انظر الاختلاف
ملاحظة: استخدم 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
، اقرأ جداول اختبار POST TEST HTML باستخدام أمر cy.table Query.
يستخلص جميع الخلايا من جدول الموضوع الحالي. ينتج عن مجموعة ثنائية الأبعاد من الأوتار.
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' ] ,
] )
انظر المواصفات 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 )
للحصول على العمود الأول مرتبط في صفيف واحد (بدلاً من صفيف 1 × 1 صفائف)
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 و Back. إذا كنت ترغب في التحويل باستخدام entries
fromEntries
، أضف وسيطة:
cy . wrap ( new URLSearchParams ( searchParams ) ) . toPlainObject ( 'entries' )
في Cypress v12 cy.invoke
أصبح استعلامًا ، مما جعل العمل مع أساليب غير متزامنة غير عملي حقًا. cy.invokeOnce
هو عودة الطريقة القديمة لاستدعاء الطريقة وإعطاء القيمة التي تم حلها.
cy . wrap ( app )
// app.fetchName is an asynchronous method
// that returns a Promise
. invokeOnce ( 'fetchName' )
. should ( 'equal' , 'My App' )
انظر المواصفات المحتوية على 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.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 => ... )
تتضمن هذه الحزمة تعريفات الأوامر TypeScript لأوامرها المخصصة في أوامر الملف/index.d.ts. لاستخدامه من مواصفات JavaScript الخاصة بك:
/// <reference types="cypress-map" />
إذا كنت تستخدم TypeScript ، فقم بتضمين هذه الوحدة في قائمة الأنواع الخاصة بك
{
"compilerOptions" : {
"types" : [ " cypress " , " cypress-map " ]
}
}
رمز المصدر موجود في مجلد SRC/أوامر. ينتج أمر Build Code ES5 الذي ينتقل إلى مجلد commands
(لا ينبغي فحصه في عنصر التحكم في التعليمات البرمجية المصدر). يتضمن package.json
في توزيع NPM commands
بالإضافة إلى أنواع ملف src/commands/index.d.ts
.
should(callback)
على الذبابة. ملاحظة: لا تحتوي هذه الوحدة على طريقة filter
لأن Cypress API لديها أوامر الاستعلام cy.filter و cy.invoke التي يمكنك استخدامها لتصفية العناصر في كائن jQuery أو عناصر في صفيف. انظر الأمثلة في Filter.cy.js Spec. شاهد عناصر مرشح الفيديو والعناصر مع إعادة المحاولة.
المؤلف: gleb bahmutov <[email protected]> © 2022
الترخيص: معهد ماساتشوستس للتكنولوجيا - افعل أي شيء بالرمز ، لكن لا تلومني إذا لم ينجح ذلك.
الدعم: إذا وجدت أي مشاكل في هذه الوحدة ، أو البريد الإلكتروني / التغريد / المفتوح على github