انتقل إلى المحتوى الرئيسي

المحددات

يوفر بروتوكول WebDriver عدة استراتيجيات محددات للاستعلام عن عنصر. يبسط WebdriverIO هذه الاستراتيجيات للحفاظ على بساطة اختيار العناصر. يرجى ملاحظة أنه على الرغم من أن أمر الاستعلام عن العناصر يسمى $ و $$، إلا أنه ليس له علاقة بـ jQuery أو محرك محدد Sizzle.

على الرغم من وجود العديد من المحددات المختلفة المتاحة، فإن عددًا قليلاً منها فقط يوفر طريقة مرنة للعثور على العنصر المناسب. على سبيل المثال، بالنظر إلى الزر التالي:

<button
id="main"
class="btn btn-large"
name="submission"
role="button"
data-testid="submit"
>
Submit
</button>

نحن نوصي و__لا نوصي__ بالمحددات التالية:

المحددتوصيةملاحظات
$('button')🚨 أبدًاالأسوأ - عام جدًا، بدون سياق.
$('.btn.btn-large')🚨 أبدًاسيء. مرتبط بالتنسيق. عرضة للتغيير بشكل كبير.
$('#main')⚠️ نادرًاأفضل. لكنه لا يزال مرتبطًا بالتنسيق أو مستمعي أحداث JS.
$(() => document.queryElement('button'))⚠️ نادرًااستعلام فعال، معقد للكتابة.
$('button[name="submission"]')⚠️ نادرًامرتبط بسمة name التي لها دلالات HTML.
$('button[data-testid="submit"]')✅ جيديتطلب سمة إضافية، غير متصل بإمكانية الوصول.
$('aria/Submit') أو $('button=Submit')✅ دائمًاالأفضل. يشبه كيفية تفاعل المستخدم مع الصفحة. يوصى باستخدام ملفات الترجمة الخاصة بواجهتك الأمامية حتى لا تفشل اختباراتك أبدًا عند تحديث الترجمات

محدد استعلام CSS

إذا لم يتم الإشارة إلى خلاف ذلك، سيستعلم WebdriverIO عن العناصر باستخدام نمط محدد CSS، على سبيل المثال:

selectors/example.js
loading...

نص الرابط

للحصول على عنصر رابط بنص محدد فيه، استعلم عن النص الذي يبدأ بعلامة يساوي (=).

على سبيل المثال:

selectors/example.html
loading...

يمكنك الاستعلام عن هذا العنصر عن طريق الاتصال:

selectors/example.js
loading...

نص رابط جزئي

للعثور على عنصر رابط يتطابق نصه المرئي جزئيًا مع قيمة البحث الخاصة بك، استعلم عنه باستخدام *= في مقدمة سلسلة الاستعلام (مثل *=driver).

يمكنك الاستعلام عن العنصر من المثال أعلاه أيضًا بالاتصال:

selectors/example.js
loading...

ملاحظة: لا يمكنك مزج استراتيجيات محدد متعددة في محدد واحد. استخدم استعلامات عناصر متسلسلة متعددة للوصول إلى نفس الهدف، على سبيل المثال:

const elem = await $('header h1*=Welcome') // لا يعمل!!!
// استخدم بدلاً من ذلك
const elem = await $('header').$('*=driver')

عنصر بنص معين

يمكن تطبيق نفس التقنية على العناصر أيضًا. بالإضافة إلى ذلك، من الممكن أيضًا إجراء مطابقة غير حساسة لحالة الأحرف باستخدام .= أو .*= داخل الاستعلام.

على سبيل المثال، إليك استعلام لعنوان من المستوى 1 مع النص "Welcome to my Page":

selectors/example.html
loading...

يمكنك الاستعلام عن هذا العنصر عن طريق الاتصال:

selectors/example.js
loading...

أو استخدام استعلام نص جزئي:

selectors/example.js
loading...

نفس الشيء يعمل لأسماء id و class:

selectors/example.html
loading...

يمكنك الاستعلام عن هذا العنصر عن طريق الاتصال:

selectors/example.js
loading...

ملاحظة: لا يمكنك مزج استراتيجيات محدد متعددة في محدد واحد. استخدم استعلامات عناصر متسلسلة متعددة للوصول إلى نفس الهدف، على سبيل المثال:

const elem = await $('header h1*=Welcome') // لا يعمل!!!
// استخدم بدلاً من ذلك
const elem = await $('header').$('h1*=Welcome')

اسم العلامة

للاستعلام عن عنصر بعلامة محددة، استخدم <tag> أو <tag />.

selectors/example.html
loading...

يمكنك الاستعلام عن هذا العنصر عن طريق الاتصال:

selectors/example.js
loading...

سمة الاسم

للاستعلام عن العناصر ذات سمة اسم محددة، يمكنك إما استخدام محدد CSS3 عادي أو استراتيجية الاسم المقدمة من JSONWireProtocol عن طريق تمرير شيء مثل [name="some-name"] كمعامل محدد:

selectors/example.html
loading...
selectors/example.js
loading...

ملاحظة: استراتيجية المحدد هذه مهملة وتعمل فقط في المتصفحات القديمة التي تعمل بواسطة بروتوكول JSONWireProtocol أو باستخدام Appium.

xPath

من الممكن أيضًا الاستعلام عن العناصر عبر xPath محدد.

محدد xPath لديه تنسيق مثل //body/div[6]/div[1]/span[1].

selectors/xpath.html
loading...

يمكنك الاستعلام عن الفقرة الثانية عن طريق الاتصال:

selectors/example.js
loading...

يمكنك استخدام xPath أيضًا للتنقل لأعلى ولأسفل في شجرة DOM:

selectors/example.js
loading...

محدد اسم إمكانية الوصول

الاستعلام عن العناصر بواسطة اسمها المتاح. الاسم المتاح هو ما يتم إعلانه بواسطة قارئ الشاشة عندما يتلقى هذا العنصر التركيز. يمكن أن تكون قيمة الاسم المتاح كلاً من المحتوى المرئي أو بدائل النص المخفية.

معلومات

يمكنك قراءة المزيد عن هذا المحدد في منشور مدونة الإصدار

الجلب بواسطة aria-label

selectors/aria.html
loading...
selectors/example.js
loading...

الجلب بواسطة aria-labelledby

selectors/aria.html
loading...
selectors/example.js
loading...

الجلب بواسطة المحتوى

selectors/aria.html
loading...
selectors/example.js
loading...

الجلب بواسطة العنوان

selectors/aria.html
loading...
selectors/example.js
loading...

الجلب بواسطة خاصية alt

selectors/aria.html
loading...
selectors/example.js
loading...

ARIA - سمة الدور

للاستعلام عن العناصر استنادًا إلى أدوار ARIA، يمكنك تحديد دور العنصر مباشرة مثل [role=button] كمعامل محدد:

selectors/aria.html
loading...
selectors/example.js
loading...

سمة ID

استراتيجية المحدد "id" غير مدعومة في بروتوكول WebDriver، يجب على المرء استخدام استراتيجيات محدد CSS أو xPath بدلاً من ذلك للعثور على العناصر باستخدام المعرف.

ومع ذلك، قد تظل بعض برامج التشغيل (مثل محرك Appium You.i) تدعم هذا المحدد.

صيغ المحدد المدعومة حاليًا لـ ID هي:

//css locator
const button = await $('#someid')
//xpath locator
const button = await $('//*[@id="someid"]')
//id strategy
// Note: works only in Appium or similar frameworks which supports locator strategy "ID"
const button = await $('id=resource-id/iosname')

دالة JS

يمكنك أيضًا استخدام دوال JavaScript لجلب العناصر باستخدام واجهات برمجة التطبيقات الأصلية للويب. بالطبع، يمكنك فعل ذلك فقط داخل سياق الويب (على سبيل المثال، browser، أو سياق الويب في الجوال).

بالنظر إلى بنية HTML التالية:

selectors/js.html
loading...

يمكنك الاستعلام عن العنصر الشقيق لـ #elem على النحو التالي:

selectors/example.js
loading...

المحددات العميقة

تحذير

ابتداءً من v9 من WebdriverIO، لا حاجة لهذا المحدد الخاص حيث يخترق WebdriverIO تلقائيًا DOM الظل. يوصى بالهجرة بعيدًا عن هذا المحدد عن طريق إزالة >>> من أمامه.

تعتمد العديد من تطبيقات الواجهة الأمامية بشكل كبير على العناصر ذات DOM الظل. من الناحية التقنية، من المستحيل الاستعلام عن العناصر داخل DOM الظل بدون حلول بديلة. كانت shadow$ وshadow$$ من هذه الحلول البديلة التي كانت لها قيود. مع المحدد العميق، يمكنك الآن الاستعلام عن جميع العناصر داخل أي DOM ظل باستخدام أمر الاستعلام الشائع.

بفرض أن لدينا تطبيق ذو البنية التالية:

مثال Chrome

باستخدام هذا المحدد، يمكنك الاستعلام عن عنصر <button /> المتداخل في DOM ظل آخر، على سبيل المثال:

selectors/example.js
loading...

محددات الجوال

بالنسبة لاختبار الجوال الهجين، من المهم أن يكون خادم الأتمتة في السياق الصحيح قبل تنفيذ الأوامر. لأتمتة الإيماءات، يجب تعيين برنامج التشغيل بشكل مثالي إلى السياق الأصلي. ولكن لاختيار العناصر من DOM، سيحتاج برنامج التشغيل إلى تعيين إلى سياق webview للمنصة. فقط بعد ذلك يمكن استخدام الطرق المذكورة أعلاه.

بالنسبة لاختبار الجوال الأصلي، لا يوجد تبديل بين السياقات، حيث يجب عليك استخدام استراتيجيات الجوال واستخدام تقنية أتمتة الجهاز الأساسية مباشرة. هذا مفيد بشكل خاص عندما يحتاج الاختبار إلى بعض التحكم الدقيق في العثور على العناصر.

Android UiAutomator

يوفر إطار عمل UI Automator في Android عددًا من الطرق للعثور على العناصر. يمكنك استخدام واجهة برمجة تطبيقات UI Automator، وخاصة فئة UiSelector لتحديد مواقع العناصر. في Appium، ترسل كود Java، كسلسلة، إلى الخادم، الذي ينفذه في بيئة التطبيق، مما يؤدي إلى إرجاع العنصر أو العناصر.

const selector = 'new UiSelector().text("Cancel").className("android.widget.Button")'
const button = await $(`android=${selector}`)
await button.click()

Android DataMatcher و ViewMatcher (Espresso فقط)

توفر استراتيجية DataMatcher في Android طريقة للعثور على العناصر بواسطة Data Matcher

const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"]
})
await menuItem.click()

وبالمثل View Matcher

const menuItem = await $({
"name": "hasEntry",
"args": ["title", "ViewTitle"],
"class": "androidx.test.espresso.matcher.ViewMatchers"
})
await menuItem.click()

Android View Tag (Espresso فقط)

توفر استراتيجية علامة العرض طريقة مناسبة للعثور على العناصر من خلال علامة الخاصة بها.

const elem = await $('-android viewtag:tag_identifier')
await elem.click()

iOS UIAutomation

عند أتمتة تطبيق iOS، يمكن استخدام إطار عمل أتمتة واجهة المستخدم من Apple للعثور على العناصر.

تحتوي واجهة برمجة التطبيقات JavaScript هذه على أساليب للوصول إلى العرض وكل شيء عليه.

const selector = 'UIATarget.localTarget().frontMostApp().mainWindow().buttons()[0]'
const button = await $(`ios=${selector}`)
await button.click()

يمكنك أيضًا استخدام البحث بالمسند ضمن أتمتة واجهة مستخدم iOS في Appium لتحسين اختيار العنصر بشكل أكبر. راجع هنا للحصول على التفاصيل.

سلاسل المسند و سلاسل الفئة لـ iOS XCUITest

مع iOS 10 وما فوق (باستخدام برنامج تشغيل XCUITest)، يمكنك استخدام سلاسل المسند:

const selector = `type == 'XCUIElementTypeSwitch' && name CONTAINS 'Allow'`
const switch = await $(`-ios predicate string:${selector}`)
await switch.click()

و سلاسل الفئة:

const selector = '**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton'
const button = await $(`-ios class chain:${selector}`)
await button.click()

معرف إمكانية الوصول

تم تصميم استراتيجية محدد accessibility id لقراءة معرف فريد لعنصر واجهة المستخدم. هذا له ميزة عدم التغيير أثناء الترجمة أو أي عملية أخرى قد تغير النص. بالإضافة إلى ذلك، يمكن أن تكون مساعدة في إنشاء اختبارات عبر الأنظمة الأساسية، إذا كانت العناصر التي هي وظيفيًا نفسها لها نفس معرف إمكانية الوصول.

  • بالنسبة لـ iOS، هذا هو accessibility identifier الذي وضعته Apple هنا.
  • بالنسبة لـ Android، يتم تعيين accessibility id إلى content-description للعنصر، كما هو موضح هنا.

بالنسبة لكلا المنصتين، فإن الحصول على عنصر (أو عناصر متعددة) بواسطة accessibility id هو عادة الطريقة الأفضل. إنها أيضًا الطريقة المفضلة على استراتيجية name المهملة.

const elem = await $('~my_accessibility_identifier')
await elem.click()

اسم الفئة

استراتيجية class name هي سلسلة تمثل عنصر واجهة المستخدم في العرض الحالي.

  • بالنسبة لـ iOS، إنه الاسم الكامل لفئة UIAutomation، وسيبدأ بـ UIA-، مثل UIATextField لحقل نص. يمكن العثور على مرجع كامل هنا.
  • بالنسبة لـ Android، إنه الاسم المؤهل بالكامل لفئة UI Automator class، مثل android.widget.EditText لحقل نص. يمكن العثور على مرجع كامل هنا.
  • بالنسبة لـ Youi.tv، إنه الاسم الكامل لفئة Youi.tv، وسيبدأ بـ CYI-، مثل CYIPushButtonView لعنصر زر الدفع. يمكن العثور على مرجع كامل في صفحة GitHub الخاصة بمحرك You.i
// مثال iOS
await $('UIATextField').click()
// مثال Android
await $('android.widget.DatePicker').click()
// مثال Youi.tv
await $('CYIPushButtonView').click()

سلسلة المحددات

إذا كنت تريد أن تكون أكثر تحديدًا في استعلامك، يمكنك تسلسل المحددات حتى تجد العنصر الصحيح. إذا استدعيت element قبل الأمر الفعلي، يبدأ WebdriverIO الاستعلام من ذلك العنصر.

على سبيل المثال، إذا كان لديك بنية DOM مثل:

<div class="row">
<div class="entry">
<label>Product A</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product B</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
<div class="entry">
<label>Product C</label>
<button>Add to cart</button>
<button>More Information</button>
</div>
</div>

وتريد إضافة المنتج B إلى عربة التسوق، سيكون من الصعب القيام بذلك باستخدام محدد CSS فقط.

مع تسلسل المحدد، الأمر أسهل بكثير. ببساطة حدد العنصر المطلوب خطوة بخطوة:

await $('.row .entry:nth-child(2)').$('button*=Add').click()

محدد صورة Appium

باستخدام استراتيجية محدد -image، من الممكن إرسال Appium ملف صورة يمثل عنصرًا تريد الوصول إليه.

تنسيقات الملفات المدعومة jpg,png,gif,bmp,svg

يمكن العثور على المرجع الكامل هنا

const elem = await $('./file/path/of/image/test.jpg')
await elem.click()

ملاحظة: الطريقة التي يعمل بها Appium مع هذا المحدد هي أنه سيقوم داخليًا بأخذ لقطة شاشة (للتطبيق) ويستخدم محدد الصورة المقدم للتحقق مما إذا كان يمكن العثور على العنصر في تلك اللقطة (للتطبيق).

كن على دراية بحقيقة أن Appium قد يغير حجم لقطة الشاشة (للتطبيق) المأخوذة لجعلها تتطابق مع حجم CSS لشاشة (التطبيق) الخاصة بك (سيحدث هذا على أجهزة iPhone ولكن أيضًا على أجهزة Mac بشاشة Retina لأن DPR أكبر من 1). سيؤدي هذا إلى عدم العثور على تطابق لأن محدد الصورة المقدم قد يكون مأخوذًا من لقطة الشاشة الأصلية. يمكنك إصلاح ذلك عن طريق تحديث إعدادات خادم Appium، راجع وثائق Appium للإعدادات وهذا التعليق للحصول على شرح مفصل.

محددات React

يوفر WebdriverIO طريقة لاختيار مكونات React استنادًا إلى اسم المكون. للقيام بذلك، لديك خيار من أمرين: react$ و react$$.

تسمح لك هذه الأوامر باختيار المكونات من React VirtualDOM وإعادة إما عنصر WebdriverIO واحد أو مصفوفة من العناصر (اعتمادًا على الدالة المستخدمة).

ملاحظة: الأوامر react$ و react$$ متشابهة في الوظائف، باستثناء أن react$$ سترجع جميع الحالات المطابقة كمصفوفة من عناصر WebdriverIO، وسترجع react$ أول حالة تم العثور عليها.

مثال أساسي

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent() {
return (
<div>
MyComponent
</div>
)
}

function App() {
return (<MyComponent />)
}

ReactDOM.render(<App />, document.querySelector('#root'))

في الكود أعلاه، هناك حالة MyComponent بسيطة داخل التطبيق، الذي يقوم React بعرضه داخل عنصر HTML مع id="root".

باستخدام أمر browser.react$، يمكنك اختيار حالة من MyComponent:

const myCmp = await browser.react$('MyComponent')

الآن بعد أن لديك عنصر WebdriverIO مخزن في متغير myCmp، يمكنك تنفيذ أوامر العنصر عليه.

تصفية المكونات

تسمح المكتبة التي يستخدمها WebdriverIO داخليًا بتصفية اختيارك حسب الخصائص و/أو حالة المكون. للقيام بذلك، تحتاج إلى تمرير وسيطة ثانية للخصائص و/أو وسيطة ثالثة للحالة إلى أمر المتصفح.

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent(props) {
return (
<div>
Hello { props.name || 'World' }!
</div>
)
}

function App() {
return (
<div>
<MyComponent name="WebdriverIO" />
<MyComponent />
</div>
)
}

ReactDOM.render(<App />, document.querySelector('#root'))

إذا كنت تريد اختيار حالة MyComponent التي لها خاصية name كـ WebdriverIO، يمكنك تنفيذ الأمر على النحو التالي:

const myCmp = await browser.react$('MyComponent', {
props: { name: 'WebdriverIO' }
})

إذا كنت تريد تصفية اختيارنا حسب الحالة، فإن أمر browser سيبدو كما يلي:

const myCmp = await browser.react$('MyComponent', {
state: { myState: 'some value' }
})

التعامل مع React.Fragment

عند استخدام أمر react$ لاختيار شظايا React، سيعيد WebdriverIO أول عنصر فرعي لهذا المكون كعقدة المكون. إذا كنت تستخدم react$$، ستتلقى مصفوفة تحتوي على جميع عقد HTML داخل الشظايا التي تطابق المحدد.

// index.jsx
import React from 'react'
import ReactDOM from 'react-dom'

function MyComponent() {
return (
<React.Fragment>
<div>
MyComponent
</div>
<div>
MyComponent
</div>
</React.Fragment>
)
}

function App() {
return (<MyComponent />)
}

ReactDOM.render(<App />, document.querySelector('#root'))

بالنظر إلى المثال أعلاه، هذه هي الطريقة التي ستعمل بها الأوامر:

await browser.react$('MyComponent') // يعيد عنصر WebdriverIO للـ <div /> الأول
await browser.react$$('MyComponent') // يعيد عناصر WebdriverIO للمصفوفة [<div />, <div />]

ملاحظة: إذا كان لديك حالات متعددة من MyComponent وكنت تستخدم react$$ لاختيار مكونات الشظايا هذه، فسيتم إرجاعك مصفوفة أحادية البعد لجميع العقد. بمعنى آخر، إذا كان لديك 3 حالات <MyComponent />، فسيتم إرجاع مصفوفة تحتوي على ستة عناصر WebdriverIO.

استراتيجيات المحدد المخصصة

إذا كان تطبيقك يتطلب طريقة محددة لجلب العناصر، يمكنك تحديد استراتيجية محدد مخصصة بنفسك يمكنك استخدامها مع custom$ و custom$$. لذلك قم بتسجيل استراتيجيتك مرة واحدة في بداية الاختبار، على سبيل المثال في خطاف before:

queryElements/customStrategy.js
loading...

بالنظر إلى مقتطف HTML التالي:

queryElements/example.html
loading...

ثم استخدمه عن طريق الاتصال:

queryElements/customStrategy.js
loading...

ملاحظة: هذا يعمل فقط في بيئة ويب يمكن فيها تشغيل الأمر execute.

Welcome! How can I help?

WebdriverIO AI Copilot