पेज ऑब्जेक्ट पैटर्न
WebdriverIO का वर्जन 5 पेज ऑब्जेक्ट पैटर्न सपोर्ट को ध्यान में रखकर डिज़ाइन किया गया था। "एलिमेंट्स को फर्स्ट क्लास सिटीज़न" के सिद्धांत को पेश करके, अब इस पैटर्न का उपयोग करके बड़े टेस्ट सूट बनाना संभव है।
पेज ऑब्जेक्ट्स बनाने के लिए कोई अतिरिक्त पैकेज आवश्यक नहीं हैं। यह पता चला है कि साफ, आधुनिक क्लासेज हमें सभी आवश्यक फीचर्स प्रदान करती हैं:
- पेज ऑब्जेक्ट्स के बीच इनहेरिटेंस
- एलिमेंट्स की लेज़ी लोडिंग
- मेथड्स और एक्शन्स का एनकैप्सुलेशन
पेज ऑब्जेक्ट्स का उपयोग करने का लक्ष्य वास्तविक टेस्ट से किसी भी पेज की जानकारी को अलग करना है। आदर्श रूप से, आपको सभी सेलेक्टर्स या विशिष्ट निर्देश जो किसी निश्चित पेज के लिए अद्वितीय हैं, उन्हें पेज ऑब्जेक्ट में स्टोर करना चाहिए, ताकि आप अपने पेज को पूरी तरह से रीडिज़ाइन करने के बाद भी अपना टेस्ट चला सकें।
पेज ऑब्जेक्ट बनाना
सबसे पहले, हमें एक मुख्य पेज ऑब्जेक्ट की आवश्यकता है जिसे हम Page.js
कहते हैं। इसमें सामान्य सेलेक्टर्स या मेथड्स होंगे जिन्हें सभी पेज ऑब्जेक्ट्स इनहेरिट करेंगे।
// Page.js
export default class Page {
constructor() {
this.title = 'My Page'
}
async open (path) {
await browser.url(path)
}
}
हम हमेशा पेज ऑब्जेक्ट का एक इंस्टेंस export
करेंगे, और कभी भी टेस्ट में उस इंस्टेंस को नहीं बनाएंगे। चूंकि हम एंड-टू-एंड टेस्ट लिख रहे हैं, इसलिए हम हमेशा पेज को एक स्टेटलेस कंस्ट्रक्ट के रूप में मानते हैं - जैसे कि प्रत्येक HTTP अनुरोध एक स्टेटलेस कंस्ट्रक्ट है।
निश्चित रूप से, ब्राउज़र सेशन जानकारी ले जा सकता है और इसलिए विभिन्न सेशन के आधार पर अलग-अलग पेज प्रदर्शित कर सकता है, लेकिन यह पेज ऑब्जेक्ट के भीतर प्रतिबिंबित नहीं होना चाहिए। इस प्रकार के स्टेट परिवर्तन आपके वास्तविक टेस्ट में होने चाहिए।
आइए पहले पेज का टेस्टिंग शुरू करें। डेमो उद्देश्यों के लिए, हम Elemental Selenium द्वारा The Internet वेबसाइट का उपयोग गिनी पिग के रूप में करते हैं। आइए लॉगिन पेज के लिए एक पेज ऑब्जेक्ट उदाहरण बनाने का प्रयास करें।
अपने सेलेक्टर्स को Get
करना
पहला कदम हमारे login.page
ऑब्जेक्ट में आवश्यक सभी महत्वपूर्ण सेलेक्टर्स को गेटर फंक्शन के रूप में लिखना है:
// login.page.js
import Page from './page'
class LoginPage extends Page {
get username () { return $('#username') }
get password () { return $('#password') }
get submitBtn () { return $('form button[type="submit"]') }
get flash () { return $('#flash') }
get headerLinks () { return $$('#header a') }
async open () {
await super.open('login')
}
async submit () {
await this.submitBtn.click()
}
}
export default new LoginPage()
सेलेक्टर्स को गेटर फंक्शन में परिभाषित करना थोड़ा अजीब लग सकता है, लेकिन यह वास्तव में उपयोगी है। ये फंक्शन जब आप प्रॉपर्टी एक्सेस करते हैं तब इवैल्युएट होते हैं, न कि जब आप ऑब्जेक्ट को जनरेट करते हैं। इससे आप हमेशा एलिमेंट पर कोई एक्शन करने से पहले उस एलिमेंट का अनुरोध करते हैं।
कमांड्स को चेन करना
WebdriverIO आंतरिक रूप से कमांड के अंतिम परिणाम को याद रखता है। यदि आप एक एलिमेंट कमांड को एक एक्शन कमांड के साथ चेन करते हैं, तो यह पिछले कमांड से एलिमेंट को ढूंढता है और परिणाम का उपयोग एक्शन को एक्जीक्यूट करने के लिए करता है। इसके साथ आप सेलेक्टर (पहला पैरामीटर) को हटा सकते हैं और कमांड इतना सरल दिखता है:
await LoginPage.username.setValue('Max Mustermann')
जो बुनियादी रूप से इसके समान है:
let elem = await $('#username')
await elem.setValue('Max Mustermann')
या
await $('#username').setValue('Max Mustermann')
अपने टेस्ट में पेज ऑब्जेक्ट्स का उपयोग करना
पेज के लिए आवश्यक एलिमेंट्स और मेथड्स को परिभाषित करने के बाद, आप इसके लिए टेस्ट लिखना शुरू कर सकते हैं। पेज ऑब्जेक्ट का उपयोग करने के लिए आपको import
(या require
) करने की आवश्यकता है। बस इतना ही!
चूंकि आपने पेज ऑब्जेक्ट का पहले से बनाया गया इंस्टेंस एक्सपोर्ट किया है, इसे इम्पोर्ट करने से आप इसे तुरंत उपयोग करना शुरू कर सकते हैं।
यदि आप एक असर्शन फ्रेमवर्क का उपयोग करते हैं, तो आपके टेस्ट और भी अधिक एक्सप्रेसिव हो सकते हैं:
// login.spec.js
import LoginPage from '../pageobjects/login.page'
describe('login form', () => {
it('should deny access with wrong creds', async () => {
await LoginPage.open()
await LoginPage.username.setValue('foo')
await LoginPage.password.setValue('bar')
await LoginPage.submit()
await expect(LoginPage.flash).toHaveText('Your username is invalid!')
})
it('should allow access with correct creds', async () => {
await LoginPage.open()
await LoginPage.username.setValue('tomsmith')
await LoginPage.password.setValue('SuperSecretPassword!')
await LoginPage.submit()
await expect(LoginPage.flash).toHaveText('You logged into a secure area!')
})
})
संरचनात्मक पक्ष से, स्पेक फाइल्स और पेज ऑब्जेक्ट्स को अलग-अलग डायरेक्टरी में अलग करना समझ में आता है। इसके अतिरिक्त आप प्रत्येक पेज ऑब्जेक्ट को अंत: .page.js
दे सकते हैं। इससे यह और अधिक स्पष्ट हो जाता है कि आप एक पेज ऑब्जेक्ट इम्पोर्ट कर रहे हैं।
आगे बढ़ना
यह WebdriverIO के साथ पेज ऑब्जेक्ट्स को लिखने का बुनियादी सिद्धांत है। लेकिन आप इससे कहीं अधिक जटिल पेज ऑब्जेक्ट संरचनाएँ बना सकते हैं! उदाहरण के लिए, आपके पास मोडल्स के लिए विशिष्ट पेज ऑब्जेक्ट्स हो सकते हैं, या एक बड़े पेज ऑब्जेक्ट को विभिन्न क्लासेज में विभाजित कर सकते हैं (प्रत्येक समग्र वेब पेज के एक अलग भाग का प्रतिनिधित्व करती है) जो मुख्य पेज ऑब्जेक्ट से इनहेरिट करती हैं। यह पैटर्न वास्तव में पेज की जानकारी को आपके टेस्ट से अलग करने के लिए बहुत सारे अवसर प्रदान करता है, जो उन समय में आपके टेस्ट सूट को संरचित और स्पष्ट रखने के लिए महत्वपूर्ण है जहां प्रोजेक्ट और टेस्ट की संख्या बढ़ती है।
आप इस उदाहरण (और अधिक पेज ऑब्जेक्ट उदाहरणों) को GitHub पर example
फोल्डर में पा सकते हैं।