WebdriverIO testavimo framework

Kas tai per žvėris ir kodėl turėtumėte apie jį žinoti

Automatizuoto testavimo pasaulyje yra daugybė įrankių, kurie žada palengvinti gyvenimą, bet dažnai tik prideda naujų galvos skausmų. WebdriverIO yra vienas iš tų framework’ų, kuris iš tikrųjų veikia taip, kaip turėtų veikti. Jei kada nors bandėte automatizuoti naršyklės testavimą ir jutote, kad tai kaip bandymas išmokyti katę atsinešti laikraštį – WebdriverIO gali būti tas įrankis, kuris pagaliau viską sujungs į vieną veikiančią sistemą.

Šis framework’as yra sukurtas Node.js platformai ir leidžia rašyti automatizuotus testus naudojant JavaScript arba TypeScript. Skirtingai nuo kai kurių kitų sprendimų, kurie verčia jus mokytis visiškai naujos sintaksės ar paradigmos, WebdriverIO jaučiasi natūraliai bet kuriam frontend programuotojui. Jei mokate JavaScript, jau esate pusę kelio.

Kas iš tikrųjų įdomu – WebdriverIO nebando būti tik dar vienu Selenium wrapper’iu. Taip, jis naudoja WebDriver protokolą, bet prideda tiek daug papildomų galimybių, kad galutinis produktas yra visiškai kitokio lygio. Galite testuoti ne tik žiniatinklio aplikacijas, bet ir mobiliąsias programėles per Appium, o net ir desktop aplikacijas per Electron.

Kodėl programuotojai renkasi būtent šį framework’ą

Pirmiausia – dokumentacija. Rimtai, tai ne juokas. Kiek kartų esate susidūrę su puikiu įrankiu, kurio dokumentacija atrodo kaip parašyta 2008 metais ir nuo to laiko niekas jos neatnaujino? WebdriverIO dokumentacija yra gyva, išsami ir su realiais pavyzdžiais. Jie net turi interaktyvų setup wizard’ą, kuris padeda sukonfigūruoti projektą pagal jūsų poreikius.

Antra priežastis – ekosistema. WebdriverIO turi įtaisytą palaikymą daugeliui populiarių įrankių ir servisų. Norite integruoti su Cucumber? Prašom. Reikia Mocha ar Jest? Nėra problemų. Allure reportai? Veikia iš dėžės. Tai nėra situacija, kai turite ieškoti kažkokio pusiau palaikomo plugin’o, kuris paskutinį kartą buvo atnaujintas prieš trejus metus.

Trečia – sinchroninis kodas asinchroninėje aplinkoje. Skamba keistai, bet tai genialus sprendimas. WebdriverIO automatiškai tvarko visus promise’us, todėl jūsų testų kodas atrodo švariai ir skaitomai. Nereikia rašyti begalės `await` ar `.then()` grandinių. Tiesiog rašote komandas viena po kitos, tarsi jos būtų sinchroninės, o framework’as pasirūpina visu asinchroniniu šokiu už kulisų.

Kaip pradėti – nuo nulio iki pirmo testo

Įdiegimas yra paprastas kaip du kartus du. Jums reikia tik Node.js (rekomenduojama 16 ar naujesnė versija) ir npm arba yarn. Atidarote terminalą ir įvedate:

npm init wdio .

Šita komanda paleidžia interaktyvų konfigūracijos vedlį, kuris užduoda klausimus apie jūsų projektą. Kokią naršyklę norite naudoti? Kokį test runner’į pasirinkti? Ar reikia TypeScript palaikymo? Ar naudosite page object pattern? Viskas labai intuityviai ir su paaiškinimais.

Po kelių minučių turėsite pilnai sukonfigūruotą projektą su visais reikalingais priklausomybėmis. Framework’as sugeneruoja pavyzdinius testus, konfigūracijos failą ir net page object pavyzdžius, jei pasirinkote tą opciją. Tai kaip turėti asmeninį konsultantą, kuris padeda viską nustatyti.

Pirmas testas gali atrodyti maždaug taip:


describe('Mano pirmas testas', () => {
it('turėtų atidaryti Google ir patikrinti pavadinimą', async () => {
await browser.url('https://www.google.com')
await expect(browser).toHaveTitle('Google')
})
})

Matote? Nieko sudėtingo. Atidarote URL, patikrinat pavadinimą. Kodas skaito kaip paprasta anglų kalba, o tai yra didžiulis privalumas, kai po trijų mėnesių grįšite prie šių testų ir bandysite suprasti, ką gi čia parašėte.

Elementų paieška ir sąveika – čia viskas tampa įdomu

WebdriverIO turi labai galingą elementų paieškos sistemą. Galite naudoti CSS selektorius, XPath, teksto paiešką, arba net specialius mobilių aplikacijų selektorius. Bet kas iš tikrųjų įspūdinga – tai kaip lengvai galite dirbti su dinamiškai keičiamais elementais.

Pavyzdžiui, jei turite mygtuką, kuris kartais yra disabled, kartais ne, ir jums reikia palaukti, kol jis taps aktyvus:


const submitButton = await $('button[type="submit"]')
await submitButton.waitForEnabled({ timeout: 5000 })
await submitButton.click()

Framework’as automatiškai laukia, kol elementas taps enabled, ir tik tada spaudžia. Nereikia rašyti custom wait funkcijų ar naudoti setTimeout, kuris yra testavimo pasaulio ekvivalentas duct tape.

Dar viena nuostabi funkcija – automatinis retry mechanizmas. Jei elementas dar neatsidūrė DOM’e, WebdriverIO automatiškai bandys jį rasti kelis kartus per tam tikrą laiką. Tai išsprendžia 90% problemų, susijusių su timing issues, kurios yra pagrindinė automatizuotų testų nestabilumo priežastis.

Galite naudoti ir labai pažangius selektorius:


// Rasti elementą pagal tekstą
const link = await $('=Prisijungti')

// Rasti elementą, kuris turi tam tikrą tekstą
const heading = await $('h1*=Sveiki')

// Grandininė paieška
const menuItem = await $('.menu').$('.item=Nustatymai')

Page Object Pattern – kaip laikyti testus tvarkingus

Kai jūsų testų skaičius auga, kodas greitai tampa netvarkingu, jei nesilaikote tam tikros struktūros. Page Object Pattern yra standartas testavimo bendruomenėje, ir WebdriverIO jį puikiai palaiko.

Idėja paprasta – kiekvienam puslapiui ar komponentui sukuriate atskirą klasę, kurioje aprašote visus to puslapio elementus ir veiksmus. Vėliau testuose tiesiog naudojate šias klases, o ne tiesiogiai dirba su selektoriais.

Pavyzdys:


class LoginPage {
get usernameInput() { return $('#username') }
get passwordInput() { return $('#password') }
get submitButton() { return $('button[type="submit"]') }

async login(username, password) {
await this.usernameInput.setValue(username)
await this.passwordInput.setValue(password)
await this.submitButton.click()
}
}

export default new LoginPage()

Dabar jūsų testuose galite rašyti:


import LoginPage from './pages/login.page'

it('turėtų sėkmingai prisijungti', async () => {
await LoginPage.login('vartotojas', 'slaptažodis')
await expect(browser).toHaveUrl('/dashboard')
})

Matote skirtumą? Testas dabar skaito kaip verslo logika, o ne kaip techninis selektorių ir komandų rinkinys. Jei pasikeičia login formos struktūra, jums reikia atnaujinti tik vieną vietą – LoginPage klasę, o ne dešimtis testų.

Integracijos ir reportai – kad vadovai būtų laimingi

Vienas dalykas yra parašyti testus, visai kitas – gauti iš jų prasmingą informaciją. WebdriverIO turi puikų palaikymą įvairiems reporting įrankiams. Allure yra vienas populiariausių, ir jį integruoti yra absurdiškai paprasta.

Įdiekite reporter’į:

npm install @wdio/allure-reporter --save-dev

Pridėkite konfigūracijoje:


reporters: ['spec', ['allure', {
outputDir: 'allure-results',
disableWebdriverStepsReporting: true,
disableWebdriverScreenshotsReporting: false,
}]]

Ir viskas. Dabar po testų paleidimo gausite gražius, interaktyvius reportus su screenshot’ais, video įrašais (jei sukonfigūravote), ir detaliu kiekvieno testo vykdymo aprašymu.

Dar viena naudinga integracija – CI/CD pipeline’ai. WebdriverIO puikiai veikia su Jenkins, GitLab CI, GitHub Actions, CircleCI ir kitomis platformomis. Galite lengvai paleisti testus paraleliai keliose naršyklėse, skirtinguose OS, ir gauti rezultatus tiesiai į jūsų pull request’us.

Jei naudojate cloud testing platformas kaip BrowserStack ar Sauce Labs, WebdriverIO turi įtaisytą palaikymą ir joms. Tiesiog nurodote credentials konfigūracijoje, ir jūsų testai veikia debesyje be jokių papildomų pastangų.

Debugging – kai viskas eina ne taip

Automatizuoti testai visada turi tą momentą, kai kažkas neveikia, ir jūs sėdite žiūrėdami į ekraną galvodami „bet gi vakar veikė”. WebdriverIO turi keletą puikių debugging funkcijų, kurios išgelbsti tokiose situacijose.

Pirmiausia – `browser.debug()` komanda. Įterpiame ją bet kurioje testo vietoje:


it('testas su debug', async () => {
await browser.url('https://example.com')
await browser.debug() // Testas sustoja čia
await $('#button').click()
})

Kai testas pasiekia šią eilutę, jis sustoja ir atidaroma REPL konsolė. Galite interaktyviai vykdyti komandas, tikrinti elementus, žiūrėti kas yra DOM’e. Tai kaip turėti breakpoint’ą, bet daug galingesnį.

Antra – screenshot’ai ir video įrašai. Galite automatiškai daryti screenshot’us kiekviename žingsnyje arba tik kai testas feilina:


afterEach(async function() {
if (this.currentTest.state === 'failed') {
await browser.saveScreenshot(`./screenshots/${this.currentTest.title}.png`)
}
})

Trečia – detalūs logai. WebdriverIO gali loginti kiekvieną komandą, kiekvieną network request’ą, kiekvieną browser event’ą. Kartais tai atrodo kaip per daug informacijos, bet kai ieškote kažkokios keistos klaidos, šie logai yra neįkainojami.

Kas toliau ir kaip tobulėti su šiuo įrankiu

WebdriverIO nėra statiškas produktas – jis nuolat tobulėja. Bendruomenė yra aktyvi, naujų feature’ų atsiranda reguliariai, o dokumentacija atnaujinama kartu su kodu. Jei norite išlikti up-to-date, verta sekti jų GitHub repository ir kartais paskaityti release notes.

Praktinis patarimas – pradėkite mažai. Nerašykite iš karto šimto testų. Sukurkite kelis pagrindinius smoke testus, kurie patikrina kritines funkcijas. Įsitikinkite, kad jie veikia stabiliai. Tik tada plėskite test suite. Nestabilus testas yra blogesnis nei jokio testo, nes jis ardo pasitikėjimą visa automatizacija.

Naudokite TypeScript, jei tik įmanoma. Taip, tai prideda šiek tiek setup’o pradžioje, bet autocomplete ir type checking sutaupo neįtikėtiną kiekį laiko ilgalaikėje perspektyvoje. Ypač kai dirba komanda – type’ai veikia kaip dokumentacija, kuri niekada nesensta.

Investuokite laiko į page object struktūrą nuo pat pradžių. Gali atrodyti kaip per daug darbo paprastiems testams, bet kai projektas auga, ši struktūra tampa jūsų išgelbėjimu. Geriau praleisti valandą dabar nei savaitę po trijų mėnesių refaktorinant chaotišką kodą.

Ir paskutinis, bet ne mažiau svarbus dalykas – testai turi būti greitai. Jei jūsų test suite vykdomas valandą, niekas jo neleis prieš kiekvieną commit’ą. Optimizuokite, naudokite paralelizaciją, praleiskite nereikalingus wait’us. Greiti testai yra testai, kurie iš tikrųjų naudojami, o ne tie, kurie veikia tik CI pipeline’e naktimis.

WebdriverIO suteikia visus įrankius, kurių reikia kokybiškai automatizacijai. Framework’as nėra tobulas – nieko nėra – bet jis yra vienas geriausių sprendimų rinkoje šiandien. Jei dar nenaudojate automatizuoto testavimo arba ieškote alternatyvos esamam sprendimui, tikrai verta išbandyti. Galite būti maloniai nustebinti, kiek daug galima pasiekti su santykinai nedidelėmis pastangomis.

Daugiau

Hetzner Cloud: Europos VPS alternatyva