Protractor
Muhammad M.
Sr. SQA Analyst | ISTQB Certified | Certified in Cybersecurity | Certified Blockchain Expert | Certified Blockchain Security Professional
Quick Start - Jasmine, Selenium, & Mocha (Chai Assertions)
Protractor needs two files to run, the test or spec file, and the configuration file. For additional information, see Working with Spec and Config Files.
Prerequisites
Protractor is library built using Node.js and uses jasmine framework to create & run test. To execute the scripts, you need to have Node.js installed. You can install Protractor package using npm, this will install Node.js as well as pre-requisite.
Protractor has the capability to use multiple test frameworks like Mocha, Selenium WebDriver etc. For you, Protractor uses jasmine test framework by default to test the User Interface (UI).
For our first test script, we need to have following installed as pre-requisites:
- Standalone Selenium Server
- Java Development Kit (JDK)
Setup
Use npm to install Protractor globally with:
npm install -g protractor
This will install two command line tools, protractor and webdriver-manager. Try running protractor --version to make sure it's working.
The webdriver-manager is a helper tool to easily get an instance of a Selenium Server running. Use it to download the necessary binaries with:
webdriver-manager update
Now start up a server with:
webdriver-manager start
This will start up a Selenium Server and will output a bunch of info logs. Your Protractor test will send requests to this server to control a local browser. Leave this server running throughout the tutorial. You can see information about the status of the server at https://localhost:4444/wd/hub.
Locators
The heart and soul of test automation, is to identify the Web Controls or Web Elements or DOM objects, which ever convention you use, and then interact.
Like any other automation framework, Protractor will also support you with identifiers or technically called as Locators.
- By ID
- By Name
- By CSS
- By Model
- By Binding
examples are as follows:
// Find an element using a css selector. by.css('.className') // Find an element with the given id. by.id('elementId') // Find an element using an input name selector. by.name('element_Name') // Find an element with a certain ng-model. // Note that at the moment, this is only supported for AngularJS apps. by.model('ng-model_Name') // Find an element bound to the given variable. // Note that at the moment, this is only supported for AngularJS apps. by.binding('bindingFunction')
Multiple elements
element.all() has several helper functions:
// Number of elements. element.all(locator).count(); // Get by index (starting at 0). element.all(locator).get(index); // First and last. element.all(locator).first(); element.all(locator).last();
Actions
The element() function returns an ElementFinder Object. The ElementFinder knows how to locate the DOM element using the locator you passed in as a parameter, but it has not actually done yet. It will not contact the browser until an action method has been called.
Following actions are available:
- click()
- clear()
- sendKeys(input)
- getAttribute(attributeName)
usage examples:
var el = element(locator); // Click on the element. el.click(); // Send keys to the element (usually an input). el.sendKeys('some value'); // Clear the text in an element (usually an input). el.clear(); // Get the value of an attribute, for example, get the value of an input. el.getAttribute('AttributeName');
Now that you are aware of the basics, and ready to create your first test script.
Practice Test
Task description is to test and automate a simple workflow of Flight Booking scenario using Delta Air web portal.
Most of the code writer below is self explanatory, but in case you have any questions or would like to share your valuable input, feel free to share it with all of us (comments).
In order to define a test, the Protractor uses a function template described below:
it('Book Flight', function ()
The word "it" is actually the definition for test method and its parameters are:
- Description of the test method, its a simple text or string
- function(), is a keyword which defines the test method as a function to be executed
but for a test script, the file needs to have following declaration:
describe('Book Delta Airline Flight from DXB to BAH', function ()
so in a nutshell the overall structure of a test script would be like:The describe and it syntax is from the Jasmine framework.
browser is a global created by Protractor, which is used for browser-level commands such as navigation with browser.get.
describe('Protractor Demo App', function() { var firstNumber = element(by.model('first')); var secondNumber = element(by.model('second')); var goButton = element(by.id('gobutton')); var latestResult = element(by.binding('latest')); it('should have a title', function() { expect(browser.getTitle()).toEqual('Super Calculator'); }); it('should add one and two', function() { firstNumber.sendKeys(1); secondNumber.sendKeys(2); goButton.click(); expect(latestResult.getText()).toEqual('3'); }); });
You should see a Chrome browser window open up and navigate to the Calculator, then close itself (this should be very fast!). The test output should be 1 tests, 1 assertion, 0 failures. Congratulations, you've run your first Protractor test!
Now back to our main objective and task.
describe('Book Delta Airline Flight from DXB to BAH', function () { //Search Airport (Departure & Destination) function searchAirport(airportName, bool_SelectFirstSuggestion) { var popupCity_ToFrom = element(by.css('.modal-content')); //popup displaying flyout airport search if (bool_SelectFirstSuggestion) { expect( (popupCity_ToFrom.get().element.all(by.css('.ng-star-inserted')).first().element(by.css('')).getText()).equals(airportName) ); //Without using a variable popupCity_ToFrom.get().element.all(by.css('.ng-star-inserted')).first().click(); } else { //With using a variable var suggestion_List = popupCity_ToFrom.get().element.all(by.css('.ng-star-inserted')); suggestion_List.get(0).click(); expect( suggestion_List.get(0).getText().equals(airportName) ); } } //selecting dropdown options on the basis of text value function selectDropdownOption(lstItems, selectionByText){ var bool_ItemFound = false; for(var index=0; index < lstItems.length; index++){ if(lstItems[index].getText() == selectionByText) { lstItems[index].click(); bool_ItemFound = true break; } } expect(bool_ItemFound); } // =====> Date parameter value format should be 'dd-MMM-yyyy' && String values <====== function splitDate(dateValue) { var splitDateValues; if (dateValue != 'undefined' && typeof dateValue == 'string') { splitDateValues = dateValue.split('-'); } return splitDateValues } //--date selection // =====> Date parameter value format should be 'dd-MMM-yyyy' && String values <====== function markDateOnCalendar(strDate) { strDate = strDate.replace('-', '/'); var lst_AvailableDaysOnCalendar = element(by.css('.dl-datepicker-available-day')); for (var index = 0; index < lst_AvailableDaysOnCalendar.length; index++) { //if (lst_AvailableDaysOnCalendar[index].element(by.tagName('a')).getAttribute('aria-label').contains()) { if (lst_AvailableDaysOnCalendar[index].element(by.tagName('a')).getAttribute('data-date').contains(strDate)) { lst_AvailableDaysOnCalendar[index].click(); } } } //Click Next (month >) button to move calendar view to next month dates ==> use 1 parameter value to navigate to next // similarly click Previous (month <) button to move calendar view to previous month dates ==> use 0 parameter value to navigate to previ. function CalendarMonth_Next_Back_Action(intVal) { if (intVal == 0) { element(by.css('.dl-datepicker-0')).click(); //Previous month } if (intVal == 1) { element(by.css('.dl-datepicker-1')).click(); //Previous month } } //Recurrsive Function //On the basis of diffMonth value, the number of clicks as Next or Back button will lead to right select of month and year function navigateCalendarView_Next_Back(diffMonth) { if (diffMonth > 0) { CalendarMonth_Next_Back_Action(1); diffMonth--; } if (diffMonth < 0) { CalendarMonth_Next_Back_Action(0); diffMonth++; } return navigateCalendarView_Next_Back(indexOfDateValMonth, indexOfCalendarVwMonth, diffMonth); } //getIndex of the value for Month; in sequence function getIndex_Month_Sequence(strValueMonth) { var arrMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; arrYears.indexOf(strValueMonth) } //getIndex of the value for Year; in sequence function getIndex_Year_Sequecne(strValueYear) { var arrYears = ['2020', '2021']; //===> Limitation Schedule for current year or the next year that's it. return arrYears.indexOf(strValueYear) } //Date year & month search on Calendar View function searchDate_Year_Month(year_toSelect, month_toSelect, isFalse_for_Departure) { var calendarVW_YearValue; if (isFalse_for_Departure) { calendarVW_YearValue = element(by.css('.dl-datepicker-year-1')); } else { calendarVW_YearValue = element(by.css('.dl-datepicker-year-0')); } var diffYear = getIndex_Year_Sequecne(year_toSelect) - getIndex_Year_Sequecne(calendarVW_YearValue); var diffMonth = getIndex_Month_Sequence(month_toSelect) - getIndex_Month_Sequence(calendarVW_YearValue); if (diffYear > 0) { diffMonth += 12; } if (diffYear < 0) { diffMonth -= 12; } navigateCalendarView_Next_Back(diffMonth); } //Calendar date selection for Departure & Return // =====> Date parameter value format should be 'dd-MMM-yyyy' && String values <====== function selectDates_Departure_Return(calendarControlElement_ClassName, tripType_OneWay_Round , departureDate, returnDate) { if (departureDate != 'undefined' && ( tripType_OneWay_Round == 'Round Trip' && (returnDate != 'undefined' || returnDate != null) ) ) { //Identifying Master Container for Calendar control //ID>'input_departureDate_1'; ClassName>calendarMasterCont var calendarMasterContainer = element(by.id(calendarControlElement_ClassName)); // Click element to make Calendar Visible for date selection calendarMasterContainer.element(by.id('input_departureDate_1')).click(); // Clear default selection calendarMasterContainer.element(by.id('resetButton')).click(); //To select Departure Date first var departureSplitDate = splitDate(departureDate); searchDate_Year_Month(departureSplitDate[2], departureSplitDate[1], false); //--date > Day selection markDateOnCalendar(departureDate); //To select Return Date var returnSplitDate = splitDate(returnDate); searchDate_Year_Month(returnSplitDate[2], returnSplitDate[1], true); //--date > Day selection markDateOnCalendar(returnDate); } } it('Book Flight', function () { browser.get('https://www.delta.com/mea/en'); //First the Source/Departure element(by.id('fromAirportName')).click(); searchAirport('DXB', true); //Now the Destination/Arrival element(by.id('toAirportName')).click(); searchAirport('BAH', false); //Select Trip Type element(by.id('selectTripType')).click(); //element(by.id('selectTripType-desc')); //un-ordered list //element.all(by.tagName('li')) //the other way is to get the list of elements selectDropdownOption(element.all(by.tagName('li')), 'One Way'); //Departure and Return Date //departure date element(by.id('departureDate')).click(); //return date if Round Trip selectDates_Departure_Return('calendarMasterCont', 'Round Trip', '28-03-2020', '15-04-2020'); // 'One Way' or 'Round Trip' //select number of passengers element(by.id('passengers-val')).click(); selectDropdownOption(element(by.id('passengers-desc')).all(by.tagName('li')), '2 Passengers'); //Click Search schedule button element(by.id('btn-book-submit')).click(); }); });
Sr. SQA Analyst | ISTQB Certified | Certified in Cybersecurity | Certified Blockchain Expert | Certified Blockchain Security Professional
4 年#automation?#endtoend?#responsive?#ui #protractor?#jasmine?#mocha?#chai?