الأوامر المخصصة
إذا كنت ترغب في توسيع مثيل browser
بمجموعة خاصة بك من الأوامر، فإن طريقة المتصفح addCommand
موجودة من أجلك. يمكنك كتابة أمرك بطريقة غير متزامنة، تمامًا كما في مواصفاتك.
المعلمات
اسم الأمر
اسم يحدد الأمر وسيتم إرفاقه بنطاق المتصفح أو العنصر.
النوع: String
الدالة المخصصة
الدالة التي يتم تنفيذها عند استدعاء الأمر. نطاق this
هو إما WebdriverIO.Browser
أو WebdriverIO.Element
اعتمادًا على ما إذا كان الأمر مرتبطًا بنطاق المتصفح أو العنصر.
النوع: Function
نطاق الهدف
علامة لتحديد ما إذا كان سيتم إرفاق الأمر بنطاق المتصفح أو العنصر. إذا تم تعيينه إلى true
، سيكون الأمر أمر عنصر.
النوع: Boolean
الافتراضي: false
أمثلة
يوضح هذا المثال كيفية إضافة أمر جديد يقوم بإرجاع عنوان URL الحالي والعنوان كنتيجة واحدة. النطاق (this
) هو كائن WebdriverIO.Browser
.
browser.addCommand('getUrlAndTitle', async function (customVar) {
// `this` يشير إلى نطاق `browser`
return {
url: await this.getUrl(),
title: await this.getTitle(),
customVar: customVar
}
})
بالإضافة إلى ذلك، يمكنك توسيع مثيل العنصر بمجموعتك الخاصة من الأوامر، من خلال تمرير true
كوسيط نهائي. النطاق (this
) في هذه الحالة هو كائن WebdriverIO.Element
.
browser.addCommand("waitAndClick", async function () {
// `this` هو قيمة إرجاع $(selector)
await this.waitForDisplayed()
await this.click()
}, true)
تمنحك الأوامر المخصصة الفرصة لتجميع تسلسل محدد من الأوامر التي تستخدمها بشكل متكرر في استدعاء واحد. يمكنك تعريف أوامر مخصصة في أي نقطة في مجموعة الاختبار الخاصة بك؛ فقط تأكد من تعريف الأمر قبل استخدامه للمرة الأولى. (يعد خطاف before
في ملف wdio.conf.js
مكانًا جيدًا لإنشائها.)
بمجرد تعريفها، يمكنك استخدامها على النحو التالي:
it('should use my custom command', async () => {
await browser.url('http://www.github.com')
const result = await browser.getUrlAndTitle('foobar')
assert.strictEqual(result.url, 'https://github.com/')
assert.strictEqual(result.title, 'GitHub · Where software is built')
assert.strictEqual(result.customVar, 'foobar')
})
ملاحظة: إذا قمت بتسجيل أمر مخصص في نطاق browser
، فلن يكون الأمر متاحًا للعناصر. وبالمثل، إذا قمت بتسجيل أمر في نطاق العنصر، فلن يكون متاحًا في نطاق browser
:
browser.addCommand("myCustomBrowserCommand", () => { return 1 })
const elem = await $('body')
console.log(typeof browser.myCustomBrowserCommand) // يخرج "function"
console.log(typeof elem.myCustomBrowserCommand()) // يخرج "undefined"
browser.addCommand("myCustomElementCommand", () => { return 1 }, true)
const elem2 = await $('body')
console.log(typeof browser.myCustomElementCommand) // يخرج "undefined"
console.log(await elem2.myCustomElementCommand('foobar')) // يخرج "1"
const elem3 = await $('body')
elem3.addCommand("myCustomElementCommand2", () => { return 2 })
console.log(typeof browser.myCustomElementCommand2) // يخرج "undefined"
console.log(await elem3.myCustomElementCommand2('foobar')) // يخرج "2"
ملاحظة: إذا كنت بحاجة إلى تسلسل أمر مخصص، يجب أن ينتهي الأمر بـ $
,
browser.addCommand("user$", (locator) => { return ele })
browser.addCommand("user$", (locator) => { return ele }, true)
await browser.user$('foo').user$('bar').click()
كن حذرًا من عدم تحميل نطاق browser
بالكثير من الأوامر المخصصة.
نوصي بتعريف المنطق المخصص في كائنات الصفحة، بحيث تكون مرتبطة بصفحة معينة.
Multiremote
يعمل addCommand
بطريقة مماثلة لـ multiremote، باستثناء أن الأمر الجديد سينتشر إلى مثيلات الأطفال. يجب أن تكون حذرًا عند استخدام كائن this
لأن browser
متعدد التحكم ومثيلات أطفاله لديهم this
مختلف.
يوضح هذا المثال كيفية إضافة أمر جديد لـ multiremote.
import { multiremotebrowser } from '@wdio/globals'
multiremotebrowser.addCommand('getUrlAndTitle', async function (this: WebdriverIO.MultiRemoteBrowser, customVar: any) {
// `this` يشير إلى:
// - نطاق MultiRemoteBrowser للمتصفح
// - نطاق Browser للمثيلات
return {
url: await this.getUrl(),
title: await this.getTitle(),
customVar: customVar
}
})
multiremotebrowser.getUrlAndTitle()
/*
{
url: [ 'https://webdriver.io/', 'https://webdriver.io/' ],
title: [
'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO',
'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO'
],
customVar: undefined
}
*/
multiremotebrowser.getInstance('browserA').getUrlAndTitle()
/*
{
url: 'https://webdriver.io/',
title: 'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO',
customVar: undefined
}
*/
توسيع تعريفات النوع
مع TypeScript، من السهل توسيع واجهات WebdriverIO. أضف أنواعًا إلى أوامرك المخصصة كما يلي:
-
قم بإنشاء ملف تعريف النوع (مثال،
./src/types/wdio.d.ts
) -
أ. إذا كنت تستخدم ملف تعريف نوع على طراز الوحدة (باستخدام import/export و
declare global WebdriverIO
في ملف تعريف النوع)، تأكد من تضمين مسار الملف في خاصيةinclude
فيtsconfig.json
.ب. إذا كنت تستخدم ملفات تعريف نوع على الطراز المحيط (بدون import/export في ملفات تعريف النوع و
declare namespace WebdriverIO
للأوامر المخصصة)، تأكد من أنtsconfig.json
لا يحتوي على أي قسمinclude
، لأن هذا سيتسبب في عدم التعرف على جميع ملفات تعريف النوع غير المدرجة في قسمinclude
بواسطة typescript.
- الوحدات (باستخدام import/export)
- تعريفات النوع المحيطة (بدون تضمين tsconfig)
{
"compilerOptions": { ... },
"include": [
"./test/**/*.ts",
"./src/types/**/*.ts"
]
}
{
"compilerOptions": { ... }
}
- أضف تعريفات لأوامرك وفقًا لوضع التنفيذ الخاص بك.
- الوحدات (باستخدام import/export)
- تعريفات النوع المحيطة
declare global {
namespace WebdriverIO {
interface Browser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface MultiRemoteBrowser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface Element {
elementCustomCommand: (arg: any) => Promise<number>
}
}
}
declare namespace WebdriverIO {
interface Browser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface MultiRemoteBrowser {
browserCustomCommand: (arg: any) => Promise<void>
}
interface Element {
elementCustomCommand: (arg: any) => Promise<number>
}
}
دمج مكتبات الطرف الثالث
إذا كنت تستخدم مكتبات خارجية (مثل، للقيام باستدعاءات قاعدة البيانات) التي تدعم الوعود، فإن أحد الأساليب الجيدة لدمجها هو تغليف طرق API معينة بأمر مخصص.
عند إرجاع الوعد، يضمن WebdriverIO أنه لا يستمر في الأمر التالي حتى يتم حل الوعد. إذا تم رفض الوعد، سيطرح الأمر خطأً.
browser.addCommand('makeRequest', async (url) => {
const response = await fetch(url)
return await response.json()
})
ثم، استخدمه فقط في مواصفات اختبار WDIO الخاصة بك:
it('execute external library in a sync way', async () => {
await browser.url('...')
const body = await browser.makeRequest('http://...')
console.log(body) // يُرجع نص الاستجابة
})
ملاحظة: نتيجة أمرك المخصص هي نتيجة الوعد الذي تُرجعه.
الكتابة فوق الأوامر
يمكنك أيضًا الكتابة فوق الأوامر الأصلية باستخدام overwriteCommand
.
لا يُنصح بالقيام بذلك، لأنه قد يؤدي إلى سلوك غير متوقع للإطار!
النهج العام مشابه لـ addCommand
، الفرق الوحيد هو أن الوسيطة الأولى في دالة الأمر هي الدالة الأصلية التي أنت على وشك الكتابة فوقها. يرجى الاطلاع على بعض الأمثلة أدناه.
الكتابة فوق أوامر المتصفح
/**
* طباعة الميلي ثانية قبل الإيقاف المؤقت وإرجاع قيمتها.
*/
// 'pause' - اسم الأمر المراد الكتابة فوقه
// origPauseFunction - دالة الإيقاف المؤقت الأصلية
browser.overwriteCommand('pause', async (origPauseFunction, ms) => {
console.log(`sleeping for ${ms}`)
await origPauseFunction(ms)
return ms
})
// ثم استخدمه كما كان من قبل
console.log(`was sleeping for ${await browser.pause(1000)}`)