Protractor
Special thanks to the one who shared the idea of creating a quick guide on Protractor

Protractor

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.

  1. By ID
  2. By Name
  3. By CSS
  4. By Model
  5. 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:

  1. click()
  2. clear()
  3. sendKeys(input)
  4. 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:

  1. Description of the test method, its a simple text or string
  2. 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();


    });
});


Muhammad M.

Sr. SQA Analyst | ISTQB Certified | Certified in Cybersecurity | Certified Blockchain Expert | Certified Blockchain Security Professional

4 年

#automation?#endtoend?#responsive?#ui #protractor?#jasmine?#mocha?#chai?

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了