Upload
others
View
27
Download
0
Embed Size (px)
Citation preview
EFFECTIVE END TO END TESTING WITH
CODECEPTJS
by Michael Bodnarchuk
2018
ABOUT ME
Michael Bodnarchuk @davertWeb developer from Kyiv, UkraineLead developer of CodeceptJSAlso author of Codeception, Robo and othersTech Consultant, CTO at SDCLabs
MY EXPERIENCE
10+ years in web developmentWriting tests since 2008Languages: JavaScript, PHP, Ruby
MY VISION
Tests should be simple to write and understandTests have their priority. Don't write tests for everythingTests should follow business valuesTesting should be joyful
CODECEPTJS
CODECEPTJS
end to end testing frameworkhelpers for popular testing backendhigh-level uni�ed APIs for all backends~15K week installations
PURPOSE OF CODECEPTJS
Ideas taken from High-level BDD-style languageRun a single test over multiple backendsDon't worry about asychronity
Codeception
ARCHITECTURE
WebDriverIO Protractor Nightmare Puppeteer
ElectronWebDriver API
CODECEPTJS
Selenium Server
Firefox Browser Chrome BrowserEdge Browser
DevTools Protocol
Cloud Browsers
HELPERS
BACKENDS & DEPENDENCIES
WebDriverIO =>webdriverio packageSelenium ServerChromeDriver or GeckoDriver
Protractorprotractor packageChromeDriver
Puppeteerpuppeteer package
Nightmarenightmare package
SAMPLE SCENARIOScenario('todomvc', (I) => {
I.amOnPage('http://todomvc.com/examples/react/');
I.waitForElement('.new-todo');
I.dontSeeElement('.todo-count');
I.fillField('What needs to be done?', 'Write a guide');
I.pressKey('Enter');
I.see('Write a guide', '.todo-list');
I.see('1 item left', '.todo-count');
I.fillField('What needs to be done?', 'Write a test');
I.pressKey('Enter');
I.see('Write a test', '.todo-list');
I.see('2 items left', '.todo-count');
I.fillField('What needs to be done?', 'Write a code');
I.pressKey('Enter');
I.see('Write a code', '.todo-list');
I.see('3 items left', '.todo-count');
});
GOALS
Focus on scenario not on implementationEasy to read and writeSeparate test code from support code
FEATURES
REFACTOR TESTS!Scenario('post article', async (I, loginPage) => {
const user = await I.createUser('davert');
loginPage.login(davert);
// ..
I.see('User logged in', loginPage.messageBox);
})
FEATURES
TESTS CAN BE WRITTEN IN YOUR NATIVE LANGUAGE:Scenario('Efetuar login', (Eu) => {
Eu.estouNaPagina('http://minhaAplicacao.com.br');
Eu.preenchoOCampo("login", "[email protected]");
Eu.preenchoOCampo("senha", "123456");
Eu.clico("Entrar");
Eu.vejo("Seja bem vindo usuário!");
});
FEATURES
USE API TO PREPARE/CLEANUP DATA FOR TESTSconst user = await I.sendGetRequest('/api/users/1');
// create a post and save its Id
const postId = await I.sendPostRequest('/api/posts', { author: user.id,
BASIC CONCEPTS
Actor - object representing a person who performs a testHelper - customized actions for the actorPageObject - grouped reusable actions accross test suiteHooks:
Custom functions performed on bootstrap/terdownCustom functions handling events
FILE STRUCTUREFiles Description
codecept.json global con�g
codecept.conf.js alternative con�g
output/ temporary �les created by tests
*_test.js tests
steps.d.ts TypeScript de�nitions
steps_file.js custom actor
*_helper.js custom helper
END TO END TESTING
HOW TO RUN BROWSERS
Window Modevia Selenium Servervia ChromeDriver, MarionetteDriverPuppeteer or Nightmare with debug: true
Headless ModePuppeteerNightmareHeadless Chrome or Firefoxvia Dockerwith Xvfb (virtual framebu�er)
WHAT TO DOopen pages: I.amOnPageact: I.click, I.fillField, I.selectOption, ...assert: I.see, I.seeElement, I.dontSeewait: I.waitForElement, I.waitForText()take information from page: await I.grabTextFrom
HOW TO LOCATE ELEMENTS
CSS (most common)XPath (most powerful)Button | Link TextsField Names (most stable)Field Labels (most readable)
GOOD LOCATORS
Short (ideally id of element)Doesn't rely on element's positionStable to changes
I.seeElement('#user'); // good
I.seeElement('div>div>ul>li>span'); // bad
I.seeElement('//*[@id="listing-23891891"]/div/div/div[1]/div/div[2]/div/
WHAT TO CHECK
Text visibility on pageElements on pageURLs on page
MANAGING ASYNCHONITY
Wait for elementsWait for JavaScriptSmartWait
PRACTICE
BOOKING.COM
INSTALL CODECEPTJSnpm install codeceptjs webdriverio --save-dev
Install Selenium Server + ChromeDriver:[sudo] npm install -g selenium-standalone
selenium-standalone install
selenium-standalone start
BOOTSTRAP PROJECT./node_modules/.bin/codeceptjs init
FIRST TEST./node_modules/.bin/codeceptjs gt
Feature('Book');
Scenario('test something', (I) => {
I.amOnPage('/');
pause();
});
I.fillField('ss', 'Kyiv')
I.click('li[data-label="Kiev, Ukraine"]');
I.fillField('checkin_monthday', "09");
I.fillField('checkin_month', '07');
I.fillField('checkin_year', '07');
USE MOMENTJS TO FILL VALUESnpm i moment --save
moment = require('moment');
const checkinDate = moment().add(3, 'months');
const checkoutDate = checkinDate.add(3, 'days');
I.fillField('checkin_monthday', checkinDate.format('DD'));
I.fillField('checkin_month', checkinDate.format('MM'));
I.fillField('checkin_year', checkinDate.format('YY'));
OPEN FIRST HOTEL const hotelNames = await I.grabTextFrom('.sr-hotel__name');
const hotelName = hotelNames[0];
I.say(`I want to book at ${hotelName}`);
within('//*[@id="hotellist_inner"]/div[1]', () => {
I.see(hotelName);
I.dontSee(hotelNames[1]);
I.click(hotelName);
});
I.switchToNextTab();
I.see(hotelName, 'h2');
NEXT TASKS
Refactor to PageObjectsTry di�erent citiesFinish booking
QUESTIONS?Me: Michael BodnarchukProject: CodeceptJSWebsite: Twitter: @codeceptjs
codecept.io