सिंक से एसिंक तक
V8 में परिवर्तन के कारण WebdriverIO टीम ने को अप्रैल 2023 तक सिंक्रोनस कमांड निष्पादन को रोकने की घोषणा की। टीम संक्रमण को यथासंभव आसान बनाने के लिए कड़ी मेहनत कर रही है। इस गाइड में हम समझाते हैं कि कैसे आप धीरे-धीरे अपने टेस्ट सूट को सिंक से एसिंक में माइग्रेट कर सकते हैं। एक उदाहरण परियोजना के रूप में हम ककड़ी बॉयलरप्लेट का उपयोग करते हैं लेकिन अन्य सभी परियो जनाओं के साथ भी दृष्टिकोण समान है।
जावास्क्रिप्ट में वादे
WebdriverIO में सिंक्रोनस निष्पादन लोकप्रिय होने का कारण यह है कि यह वादों से निपटने की जटिलता को दूर करता है। विशेष रूप से यदि आप अन्य भाषाओं से आते हैं जहाँ यह अवधारणा इस तरह मौजूद नहीं है, तो यह शुरुआत में भ्रमित करने वाली हो सकती है। हालाँकि एसिंक्रोनस कोड से निपटने के लिए वादे एक बहुत शक्तिशाली उपकरण हैं और आज का जावास्क्रिप्ट इससे निपटना वास्तव में आसान बनाता है। यदि आपने कभी प्रॉमिस के साथ काम नहीं किया है, तो हम अनुशंसा करते हैं कि आप इसके लिए MDN संदर्भ गाइड देखें क्योंकि इसे यहाँ समझाना संभव नहीं होगा।
Async ट्रांजीशन
WebdriverIO टेस्टरनर एक ही टेस्ट सूट के भीतर async और सिंक निष्पादन को संभाल सकता है। इसका मतलब है कि आप धीरे-धीरे अपने परीक्षणों और पेजऑब्जेक्ट्स को अपनी गति से स्थानांतरित कर सकते हैं। उदाहरण के लिए, ककड़ी बॉयलरप्लेट ने आपके प्रोजेक्ट में कॉपी करने के लिए चरण परिभाषा का एक बड़ा सेट
परिभाषित किया है। हम आगे बढ़ सकते हैं और एक बार में एक स्टेप डेफिनिशन या एक फाइल को माइग्रेट कर सकते हैं।
WebdriverIO एक कोडमोड प्रदान करता है जो आपके सिंक कोड को async कोड में स्वचालित रूप से पूर्ण रूप से बदलने की अनुमति देता है। कोडमॉड को पहले डॉक्स में बताए अनुसार चलाएं और जरूरत पड़ने पर मैन्युअल माइग्रेशन के लिए इस गाइड का उपयोग करें।
कई मामलों में, जो कुछ करना आवश्यक है वह उस फ़ंक्शन को बनाना है जिसमें आप WebdriverIO कमांड को async
कहते हैं और प्रत्येक कमांड के सामने await
जोड़ते हैं। बॉयलरप्लेट प्रोजेक्ट में बदलने के लिए पहली फ़ाइल clearInputField.ts
को देखते हुए, हम इससे ट्रांसफ़ॉर्म करते हैं:
export default (selector: Selector) => {
$(selector).clearValue();
};
कई मामलों में, जो कुछ करना आवश्यक है वह उस फ़ंक्शन को बनाना है जिसमें आप WebdriverIO कमांड को async
कहते हैं और प्रत्येक कमांड के सामने await
जोड़ते हैं। बॉयलरप्लेट प्रोजेक्ट में बदलने के लिए पहली फ़ाइल clearInputField.ts
को देखते हुए, हम इससे ट्रांसफ़ॉर्म करते हैं:
export default async (selector: Selector) => {
await $(selector).clearValue();
};
इतना ही! आप यहाँ सभी पुनर्लेखन उदाहरणों के साथ पूरी प्रतिबद्धता देख सकते हैं:
प्रतिबद्ध:
- सभी चरण परिभाषाओं को रूपांतरित करें [af6625f]
:::जानकारी
यह संक्रमण इस बात से स्वतंत्र है कि आप टाइपस्क्रिप्ट का उपयोग करते हैं या नहीं। यदि आप टाइपस्क्रिप्ट का उपयोग करते हैं तो सुनिश्चित करें कि आप अंततः अपने tsconfig.json
में await
गुण को webdriverio/sync
से @wdio/globals/types
में बदल दें। यह भी सुनिश्चित करें कि आपका संकलन लक्ष्य कम से कम ES2018
पर सेट है।
:::
विशेष स्थितियां
:::जानकारी
यह संक्रमण इस बात से स्वतंत्र है कि आप टाइपस्क्रिप्ट का उपयोग करते हैं या नहीं। यदि आप टाइपस्क्रिप्ट का उपयोग करते हैं तो सुनिश्चित करें कि आप अंततः अपने tsconfig.json
में await
गुण को webdriverio/sync
से @wdio/globals/types
में बदल दें। यह भी सुनिश्चित करें कि आपका संकलन लक्ष्य कम से कम ES2018
पर सेट है।
:::
प्रत्येक लूप के लिए
:::जानकारी
यह संक्रमण इस बात से स्वतंत्र है कि आप टाइपस्क्रिप्ट का उपयोग करते हैं या नहीं। यदि आप टाइपस्क्रिप्ट का उपयोग करते हैं तो सुनिश्चित करें कि आप अंततः अपने tsconfig.json
में await
गुण को webdriverio/sync
से @wdio/globals/types
में बदल दें। यह भी सुनिश्चित करें कि आपका संकलन लक्ष्य कम से कम ES2018
पर सेट है।
:::
const elems = $$('div')
elems.forEach((elem) => {
elem.click()
})
प्रत्येक फ़ंक्शन को forEach
में पास करते हैं, वह एक पुनरावर्तक फ़ंक्शन है। एक समकालिक दुनिया में यह आगे बढ़ने से पहले सभी तत्वों पर क्लिक करेगा। यदि हम इसे अतुल्यकालिक कोड में बदलते हैं, तो हमें यह सुनिश्चित करना होगा कि हम निष्पादन को पूरा करने के लिए प्रत्येक इटरेटर फ़ंक्शन की प्रतीक्षा करें। async/await
जोड़कर ये पुनरावर्तक फ़ंक्शन एक वादा लौटाएंगे जिसे हल करने की आवश्यकता है। अब, प्रत्येकforEach
अब तत्वों पर पुनरावृति करने के लिए आदर्श नहीं है क्योंकि यह इटरेटर फ़ंक्शन के परिणाम को वापस नहीं करता है, जिस वादे के लिए हमें प्रतीक्षा करने की आवश्यकता है। इसलिए हमें forEach
map
से बदलने की आवश्यकता है जो उस वादे को वापस करता है। The map
as well as all other iterator methods of Arrays like find
, every
, reduce
and more are implemented so that they respect promises within the iterator functions and are therefor simplified for using them in an async context. उपरोक्त उदाहरण इस तरह रूपांतरित दिखता है:
const elems = await $$('div')
await elems.forEach((elem) => {
return elem.click()
})
प्रत्येक फ़ंक्शन को forEach
में पास करते हैं, वह एक पुनरावर्तक फ़ंक्शन है। एक समकालिक दुनिया में यह आगे बढ़ने से पहले सभी तत्वों पर क्लिक करेगा। यदि हम इसे अतुल्यकालिक कोड में बदलते हैं, तो हमें यह सुनिश्चित करना होगा कि हम निष्पादन को पूरा करने के लिए प्रत्येक इटरेटर फ़ंक्शन की प्रतीक्षा करें। async/await
जोड़कर ये पुनरावर्तक फ़ंक्शन एक वादा लौटाएंगे जिसे हल करने की आवश्यकता है। अब, प्रत्येक forEach
अब तत्वों पर पुनरावृति करने के लिए आदर्श नहीं है क्योंकि यह इटरेटर फ़ंक्शन के परिणाम को वापस नहीं करता है, जिस वादे के लिए हमें प्रतीक्षा करने की आवश्यकता है। इसलिए हमें forEach
साथ map
से बदलने की आवश्यकता है जो उस वादे को वापस करता है। map
के साथ-साथ Arrays के अन्य सभी पुनरावर्तक तरीके जैसे find
, every
, reduce
और अधिक के माध्यम से कार्यान्वित किए जाते हैं। p-पुनरावृति पैकेज और इसलिए async संदर्भ में उनका उपयोग करने के लिए सरलीकृत हैं। उपरोक्त उदाहरण इस तरह रूपांतरित दिखता है:
await browser.url('https://webdriver.io')
const h3Texts = await browser.$$('h3').map((img) => img.getText())
console.log(h3Texts);
/**
* returns:
* [
* 'Extendable',
* 'Compatible',
* 'Feature Rich',
* 'Who is using WebdriverIO?',
* 'Support for Modern Web and Mobile Frameworks',
* 'Google Lighthouse Integration',
* 'Watch Talks about WebdriverIO',
* 'Get Started With WebdriverIO within Minutes'
* ]
*/
प्रत्येक फ़ंक्शन को forEach
में पास करते हैं, वह एक पुनरावर्तक फ़ंक्शन है। एक समकालिक दुनिया में यह आगे बढ़ने से पहले सभी तत्वों पर क्लिक करेगा। यदि हम इसे अतुल्यकालिक कोड में बदलते हैं, तो हमें यह सुनिश्चित करना होगा कि हम निष्पादन को पूरा करने के लिए प्रत्येक इटरेटर फ़ंक्शन की प्रतीक्षा करें। async/await
जोड़कर ये पुनरावर्तक फ़ंक्शन एक वादा लौटाएंगे जिसे हल करने की आवश्यकता है। अब, प्रत्येक forEach
अब तत्वों पर पुनरावृति करने के लिए आदर्श नहीं है क्योंकि यह इटरेटर फ़ंक्शन के परिणाम को वापस नहीं करता है, जिस वादे के लिए हमें प्रतीक्षा करने की आवश्यकता है। इसलिए हमें forEach
साथ map
से बदलने की आवश्यकता है जो उस वादे को वापस करता है। map
के साथ-साथ Arrays के अन्य सभी पुनरावर्तक तरीके जैसे find
, every
, reduce
और अधिक के माध्यम से कार्यान्वित किए जाते हैं। p-पुनरावृति पैकेज और इसलिए async संदर्भ में उनका उपयोग करने के लिए सरलीकृत हैं। उपरोक्त उदाहरण इस तरह रूपांतरित दिखता है:
const elems = await $$('div')
for (const elem of elems) {
await elem.click()
}
WebdriverIO अभिकथन
उदाहरण के लिए सभी <h3 />
तत्वों को लाने और उनकी टेक्स्ट सामग्री प्राप्त करने के लिए, आप चला सकते हैं:
expect($('input')).toHaveAttributeContaining('class', 'form')
यदि यह बहुत जटिल लगता है तो आप लूप के लिए सरल उपयोग करने पर विचार कर सकते हैं, उदाहरण के लिए:
await expect($('input')).toHaveAttributeContaining('class', 'form')
सिंक पेजऑब्जेक्ट मेथड्स और एसिंक्स टेस्ट
अगर आप अपने टेस्ट सूट में पेजऑब्जेक्ट्स को सिंक्रोनस तरीके से लिखते रहे हैं, तो अब आप एसिंक्रोनस टेस्ट में उनका इस्तेमाल नहीं कर पाएंगे। यदि आपको सिंक और एसिंक्स दोनों परीक्षणों में PageObject विधि का उपयोग करने की आवश्यकता है, तो हम विधि को डुप्लिकेट करने और उन्हें दोनों परिवेशों के लिए ऑफ़र करने की अनुशंसा करते हैं, उदा:
class MyPageObject extends Page {
/**
* define elements
*/
get btnStart () { return $('button=Start') }
get loadedPage () { return $('#finish') }
someMethod () {
// sync code
}
someMethodAsync () {
// async version of MyPageObject.someMethod()
}
}
अगर आप अपने टेस्ट सूट में पेजऑब्जेक्ट्स को सिंक्रोनस तरीके से लिखते रहे हैं, तो अब आप एसिंक्रोनस टेस्ट में उनका इस्तेमाल नहीं कर पाएंगे। यदि आपको सिंक और एसिंक्स दोनों परीक्षणों में PageObject विधि का उपयोग करने की आवश्यकता है, तो हम विधि को डुप्लिकेट करने और उन्हें दोनों परिवेशों के लिए ऑफ़र करने की अनुशंसा करते हैं, उदा:
अगर आप अपने टेस्ट सूट में पेजऑब्जेक्ट्स को सिंक्रोनस तरीके से लिखते रहे हैं, तो अब आप एसिंक्रो नस टेस्ट में उनका इस्तेमाल नहीं कर पाएंगे। यदि आपको सिंक और एसिंक्स दोनों परीक्षणों में PageObject विधि का उपयोग करने की आवश्यकता है, तो हम विधि को डुप्लिकेट करने और उन्हें दोनों परिवेशों के लिए ऑफ़र करने की अनुशंसा करते हैं, उदा:
// before:
// MyPageObject.someMethod()
// after:
browser.call(() => MyPageObject.someMethod())
एक बार जब आप माइग्रेशन समाप्त कर लेते हैं तो आप सिंक्रोनस पेजऑब्जेक्ट विधियों को हटा सकते हैं और नामकरण को साफ कर सकते हैं।
निष्कर्ष
जैसा कि आप परिणामी पुनर्लेखन पीआर में देख सकते हैं, इस पुनर्लेखन की जट िलता काफी आसान है। याद रखें कि आप उस समय एक चरण-परिभाषा को फिर से लिख सकते हैं। WebdriverIO एक ही ढांचे में सिंक और एसिंक निष्पादन को संभालने में पूरी तरह से सक्षम है।