خدمة روكو
wdio-roku-service هي حزمة طرف ثالث، لمزيد من المعلومات يرجى زيارة GitHub | npm تقوم هذه الخدمة بتجاوز العديد من أجزاء WebdriverIO للسماح باستخدامها مع تطبيقات Roku وتوفر إمكانية الوصول إلى Roku ECP للتحكم في جهاز Roku أثناء الاختبار.
المتطلبات
روكو
قناة اختبار/channel.zip وجهاز Roku (مع تمكين وضع المطور) على نفس الشبكة مثل جهاز Mac الخاص بك.
WebdriverIO
هذا ليس منتجًا مستقلاً - يتم استخدامه كملحق إطار عمل WebdriverIO للاختبار (أو خدمة، بلغتهم). قبل استخدام هذا، يجب عليك المرور بإعداد WDIO عن طريق تشغيل npm init wdio@latest
.
عند المرور بخطوات الإعداد، حتى لا تضطر إلى التنقل عبر جميع الأسئلة/الخيارات، يمكنك اختيار التحديدات التالية أثناء مرحلة التهيئة:
- Roku Testing (ملاحظة: استخدم هذا إذا كان المستودع الخاص بك سيستخدم فقط لاختبار Roku حيث سيصبح الخدمة الافتراضية والوحيدة المثبتة. خلاف ذلك، استخدم E2E Testing حتى تتمكن من تثبيت خدمات متعددة.)
- On my local machine (E2E فقط)
- Web (E2E فقط)
- Chrome (E2E فقط)
- Mocha
- Typescript [الوحدات تعمل مع TS و JS، لذا اختر أيهما]
- autogenerate some test files (Y) -- الموقع الافتراضي
- page objects (Y) -- الموقع الافتراضي
- spec reporter
- additional plugins (N)
- Visual Testing (N)
- services (roku)
- npm install (Y)
تكوين Typescript
إذا كنت ترغب في استخدام Typescript لكتابة الاختبارات، فستحتاج إلى التأكد من تعيين الخيارات التالية في ملف tsconfig.json الذي أنشأه Webdriverio.
"moduleResolution": "nodenext",
"module": "NodeNext",
يمكنك بعد ذلك استخدام الخدمة عن طريق الاستيراد إلى اختباراتك كما هو موضح أدناه.
تكوين WDIO
حاليًا، يتم دعم الاختبار فقط لجهاز Roku واحد. مطلوب تحديثات التكوين التالية:
- يجب أن يكون
maxInstances
وmaxInstancesPerCapability
بقيمة 1. لا يتم دعم الاختبار على أجهزة متعددة تلقائيًا وسيؤدي ذلك إلى تكرار الأوامر المرسلة إلى Roku. يجب أن تكون هناك قدرة واحدة فقط.
//wdio.conf.js
export const config: WebdriverIO.Config = {
maxInstances: 1,
capabilities: [{
browserName: 'chrome'
// أو إذا كنت تريد وضع headless:
browserName: 'chrome',
'goog:chromeOptions': {
args: ['--headless', '--disable-gpu']
}
}],
//...
}
- يوصى بزيادة
waitforInterval
وwaitforTimeout
، لأن كل فترة تتضمن تنزيل ملف xml من Roku. للاستفادة أكثر من ميزةbrowser.debug()
، يمكنك أيضًا اختيار تمديد مهلة testrunner mocha إلى 5+ دقائق لغرفة التطوير.
//wdio.conf.js
export const config: WebdriverIO.Config = {
waitforTimeout: 30000,
//اختياري:
mochaOpts: {
ui: 'bdd',
timeout: 600000
},
//...
}
أنت الآن جاهز لكتابة اختبارك الأول!
import { installFromZip } from 'wdio-roku-service/install'
import { exitChannel } from 'wdio-roku-service/channel'
import { Buttons, keyPress, keySequence } from 'wdio-roku-service/controller'
describe('first test', () => {
before('On the landing screen of the test channel', async () => {
await installFromZip(process.env.ROKU_APP_PATH)
})
it('should launch to the homescreen without login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
})
after('should return to home', async () => {
await exitChannel()
})
})
من المشجع أيضًا استخدام ميزة browser.debug()
في wdio لإيقاف اختبارك مؤقتًا لأغراض التصحيح وتأليف الاختبار:
// ...
it('should launch to the homescreen without login', async () => {
await $("//LoadingIndicator").waitForDisplayed({ reverse: true })
await expect($("//ContentCarousel")).toBeDisplayed()
await browser.debug()
// يتوقف الاختبار، ويصبح REPL متاحًا للأوامر
إذا كان Chrome ليس في وضع headless، يمكنك رؤية آخر مرة تم فيها استدعاء openRokuXML()
(على الأرجح من خلال waitForX
أو expect
). باستخدام REPL في المحطة الطرفية، يمكنك استخدام أي أوامر $
صالحة، وبعض الأوامر المخصصة الرئيسية المضافة (browser.openRokuXML()
و browser.saveScreenshot('path/to/ss.jpg')
) -- فئة controller
غير مرتبطة بكائن browser
، لذلك لا يمكنك استخدامها حاليًا. لحسن الحظ، من المحتمل أنك جالس بجوار Roku ولديك جهاز تحكم عن بعد يمكنك استخدامه للتنقل والاتصال أحيانًا بـ browser.openRokuXML()
لمعرفة ما حدث لحالة الصفحة! وتذكر أن XML يعمل بشكل أصلي مع xpathing في متصفح chrome نفسه، لذلك يمكنك تقييم/تطوير المحددات الخاصة بك مباشرة في وحدة تحكم chrome أثناء التصحيح.
.env
انظر ملف .env.example
. انسخه وأعد تسميته إلى .env
داخل مشروع WebdriverIO الذي يستخدم هذه الخدمة. من المحتمل أنك ستضعه في .gitignore أيضًا.
ROKU_IP
يجب أن يكون عنوان IP لجهاز Roku الخاص بك. ستستخدم الأوامر هذا العنوان للتواصل معه. هذا مطلوب.ROKU_USER
وROKU_PW
: بيانات اعتماد تسجيل الدخول مطلوبة لتثبيت الأرشيف، و كذلك لالتقاط لقطات الشاشة.ROKU_APP_PATH
يجب أن يكون المسار المطلق لملف zip لقناة Roku.ROKU_CHANNEL_ID
يجب أن يكون معرف قناة Roku الخاصة بك (عادة ما يكون "dev").DEBUG=wdio-roku-service
سيمكّن رسائل التصحيح. قم بإزالة '#' في بداية السطر إذا كنت تريد تلك الرسائل.
الوظائف المتغيرة
المتصفح
waitUntil
سيجلب xml من Roku في كل تكرار للتحقق من التغييرات.saveScreenshot
سيقوم بتنزيل لقطة شاشة للشاشة الحالية من Roku. من الجدير بالذكر أن لقطات الشاشة هذه بتنسيق .jpg، بدلاً من .png الذي يستخدمه WebdriverIO عادةً.openRokuXML
سيجلب xml من Roku إذا كنت بحاجة إلى القيام بذلك يدويًا بدلاً من استخدام الانتظارات.
العناصر
- يتم دعم جميع عمليات الانتظار بنفس طريقة المتصفح. يتم تعيين
waitForClickable
إلىwaitForDisplayed
، وwaitForStable
إلىwaitForExist
. - لا يتم دعم
click
وdoubleClick
وmoveTo
. يجب عليك التنقل في التطبيق يدويًا. isFocused
سيتحقق من وجود سمةfocused
على العنصر بقيمة صحيحة.isDisplayed
سيتحقق من وجود سمةbounds
على العنصر، وأنvisible
ليست معينة على false. إذا تم تعيينwithinViewport
، سيتم مقارنة الحدود مع حجم شاشة Roku.getSize
وgetLocation
تأخذ القيم من سمةbounds
، وترجع 0 للحجم و -Infinity للموضع إذا لم تكن موجودة.
لم يتم تغيير الوظائف الأخرى، لكن العديد منها لا يزال يعمل كما هو متوقع.
المطابقات
تم تحديث معظم المطابقات لجلب xml أثناء الانتظار. بعضها له وظائف مختلفة قليلاً.
toBeDisplayed
وtoBeDisplayedInViewport
وtoBeFocused
وtoBeExisting
وtoBePresent
وtoExist
وtoHaveSize
وtoHaveWidth
وtoHaveHeight
وtoHaveAttribute
كلها تعمل كما هو متوقع، مع مراعاة التغييرات على العنصر.toHaveElementProperty
يتم تعيينه إلىtoHaveAttribute
.toHaveElementClass
يتحقق من سمةname
للعنصر.toHaveId
يتم تعيينه إلىtoHaveElementClass
.toHaveText
يتحقق من سمةtext
للعنصر.toHaveChildren
يتحقق من سمةchildren
للعنصر.toHaveHTML
سيتعامل مع xml كما لو كان HTML، على الرغم من أنه من المحتمل أن لا يكون مفيدًا جدًا.
ما يلي غير مدعوم حاليًا:
toBeSelected
- يمكن دعمه قريبًا بعد تحديد كيفية ظهور xml للأزرار المحددة، إذا كان هناك اختلاف.toBeChecked
- يمكن دعمه قريبًا بعد تحديد كيفية ظهور xml لمربعات الاختيار المحددة، إذا كان هناك اختلاف.toHaveComputedLabel
- إذا كان لديك ما يعادله على عناصر Roku الخاصة بك، فتحقق من السمة باستخدامtoHaveAttribute
.toHaveComputedRole
- إذا كان لديك ما يعادله على عناصر Roku الخاصة بك، فتحقق من السمة باستخدامtoHaveAttribute
.toHaveHref
- إذا كان لديك عناوين URL على عناصر Roku الخاصة بك، فتحقق من السمة باستخدامtoHaveAttribute
.toHaveStyle
- عناصر xml ليس لها أنماط.toHaveClipboardText
- هذا غير معروف.toHaveTitle
- العنوان سيكون اسم الملف المؤقت المولد عشوائيًا لـ xml.toHaveUrl
- سيكون عنوان URL هو المسار إلى ملف xml على جهاز الكمبيوتر الخاص بك.
الاستخدام
تثبيت القناة
هذا يتطلب أن يكون لقناتك معرف معين.
import { installByID } from 'wdio-roku-service/install';
async before() {
await installByID(process.env.ROKU_CHANNEL_ID);
}
تثبيت الأرشيف
يوصى بتخزين المسار في .env، خاصة إذا كان لديك عدة مطورين قد يكون لديهم مواقع و/أو أسماء ملفات مختلفة.
import { installFromZip } from 'wdio-roku-service/install';
async before() {
await installFromZip(process.env.ROKU_ARCHIVE_PATH);
}
قناة مثبتة مسبقًا
إذا كنت قد قمت بالفعل بتثبيت القناة بنفسك قبل الاختبار، فيمكنك ببساطة إطلاقها.
import { launchChannel, exitChannel } from 'wdio-roku-service/channel';
async before() {
// أغلق القناة إذا كانت مفتوحة بالفعل. إذا كانت القناة تدعم الاستئناف الفوري، فهذا سيضعها في الخلفية فقط
await exitChannel();
// استخدام معرف القناة 'dev' سيطلق التطبيق الجانبي.
await launchChannel('dev');
}
الاختبار
يوفر wdio-roku-service/controller
القدرة على إرسال ضغطات أزرار إلى Roku. keySequence
هو الأساسي، حيث يرسل عدة ضغطات أزرار متتالية.
import { Buttons, keySequence } from 'wdio-roku-service/controller';
// التنقل خلال التطبيق
await keySequence(Buttons.LEFT, Buttons.LEFT, Buttons.SELECT, Buttons.DOWN, Buttons.SELECT);
// جلب واجهة التطبيق الحالية من Roku وتحميلها في المتصفح
await browser.openRokuXML();
// أو استخدام الانتظارات، التي ستقوم بتحميل XML بشكل متكرر حتى تنتهي المهلة أو تنجح الشرط
await browser.waitUntil(condition);
await element.waitForDisplayed();
// استخدم مطابقات WDIO على XML الخاص بـ roku كما لو كان صفحة ويب
await expect(element).toHaveAttr('focused');
يحتوي wdio-roku-service/controller
أيضًا على وظائف لضغط أو تحرير الأزرار وكذلك كتابة النص في لوحة المفاتيح.
import { Buttons, keyboardInput, keyPress, keySequence } from 'wdio-roku-service/controller';
await keySequence(Buttons.DOWN, Buttons.DOWN, Buttons.SELECT);
await keyboardInput('example');
await keyPress(Buttons.ENTER);
await browser.openRokuXML();
الروابط العميقة
يوفر wdio-roku-service/channel
وظائف متعلقة بالقناة. يسمح inputChannel
بإرسال معلومات عشوائية إلى تطبيقك.
import { exitChannel, launchChannel, MediaType } from 'wdio-roku-service/channel';
await exitChannel();
await launchChannel(process.env.ROKU_CHANNEL_ID, myContent, MediaType.MOVIE, {myExtraParameter:true});
await expect(MyContent.header).toBeDisplayed();
وظائف أخرى
يوفر wdio-roku-service/info
وظائف متنوعة، مثل الحصول على أيقونة التطبيق أو العقد اليتيمة.
import { getAppIcon } from 'wdio-roku-service/info';
const response = await getAppIcon(process.env.ROKU_CHANNEL_ID);
expect(response.headers.get('Content-Type')).toBe('image/jpg');
wdio-roku-service/ecp
هو الواجهة المباشرة مع ECP إذا كنت بحاجة إلى القيام بأي شيء محدد للغاية.
import { ECP } from 'wdio-roku-service/ecp';
await ECP('search/browse?keyword=voyage&type=movie&tmsid=MV000058030000', 'POST');
المشاكل الشائعة
- عناصر Roku لديها نصوصها في سمة 'text'، وليس بين العلامات. عند استخدام المحددات، لن يعمل
$('element=Text')
مع كل عنصر تقريبًا. بدلاً من ذلك، عليك استخدام$('element[text=Text]')
.
خارطة طريق الميزات
- سيكون هناك PR مقدم قريبًا يسمح بتثبيت هذه الخدمة أثناء استبيان
npm init wdio@latest
. - حاليًا يتم تقييم اتصال Socket مع Roku بحيث يمكن إضافة المزيد من الميزات، مثل وسيلة لإيقاظ Roku النائم.
- ميزة (ميزات) وكيل الشبكة التي تسمح بالتفاعل مع نشاط الشبكة.