Protractor Interview Questions – Part-2

This is the part-2 in a series of interview questions designed and asked to candidates in interviews for Protractor. The series 1 is up already – please visit this link for the same.  
  •  I have one spec file and one conf file. I want to run it against three separate environment URLS – Dev, QA, Prod. How can I do that?

Ans : There are multiple ways of doing that. Let’s assume you have three separate environments – Dev,QA and Prod. These three environments have separate urls – for eg, the dev one has something like http://dev.abcd.company.com and the same for QA is http://qa.abcd.company.com.

Approach -1

If you want your baseUrl to change at the runtime, all you need to do is to provide this parameter in the terminal at run time. The parameters will override whatever you have put in baseurl in the conf.js file. So, you can do something like protractor baseUrl = 'http://dev.abcd.company.com' conf.js for Dev and similarly for QA, it’ll be protractor baseUrl='http://qa.abcd.company.com' conf.js

Approach-2

You can define environments in the conf.js file and based on the configuration, you can pass the URL that you want to pass. Step -1 Add a flag called paramsin your conf.js file like params :{ environment : null } Step -2 When running pass this parameter from terminal protractor params.environment = 'QA' conf.js Step – 3 In your onPrepare method, you can configure the desired url to be passed
onPrepare:function(){
   if(browser.params.environement=QA){
      browser.baseUrl="QA URL"
     }
   else{
      browser.baseUrl="Dev URL"
   }
 };
  • How to set a global variable in Protractor tests?

Ans : It can be done either using the params property in the conf.js file or directly defining using globals.variable_name in the onPrepare()method in the conf.js file. Please see this StackOverflow answer to understand how this can be done.  
  • Do you know how to run Protractor with gulp?

Ans :  Yes. It can be done. However, there are multiple ways and solutions of doing this thing. Please refer this StackOverflow post for the same.  
  • How can I run Protractor tests against two browsers at same time?

Ans : Protractor provides a flag called multiCapabilities that can be added in the conf.js file.  Let’s say I want to run a spec file against both Chrome and FF. It can be easily configured like
multiCapabilities: [{
  'browserName': 'chrome'
}, {
  'browserName': 'firefox'
}],
Here is a demo example.
  • How to create a new browser instance in your tests using Protractor?

Ans : This can be done by forking the driver instance using the forkNewDriverInstance method. It takes two parameters that can given you the selection whether to open the new driver with the same url , second one allows you to copy the mock modules from original browser. The documentation in Protractor github link is simple enough for the explanation for this.  
  • How to run a headless Chrome in Protractor?

Ans :  This can be done using the --headless flag inside the ChromeOptions in your capabilities in the conf.js file.  A simple example, inside your conf.js file, you can have this
capabilities: {
        browserName: 'chrome',

        chromeOptions: {
            args: [ "--headless", "--disable-gpu", "--window-size=800,600" ]
        }
    }
 
  • What is an onPrepare function used for in Protractor configuration?

Ans : The onPrepare method in Protractor is used for any global configuration.  
  • Explain how you can use the repeater locator in Protractor?

Ans : In Angular or Angular JS, ng-repeat tag is used for populating an HTML list – with minimal coding. Let’s take an example




<ol class="hoverEnabled godzillaEnlighterJS EnlighterJS">
 	



<li class=" odd"><span class="kw1"><div</span> <span class="kw2">ng-repeat</span><span class="kw1">=</span><span class="st0">"cat in pets"</span><span class="kw1">></span></li>




 	



<li class=" even"><span class="kw1"><span</span><span class="kw1">></span><span class="">{{cat.name}}</span><span class="kw1"></span></span></li>




 	



<li class=" odd"><span class="kw1"><span</span><span class="kw1">></span><span class="">{{cat.age}}</span><span class="kw1"></span></span></li>




 	



<li class=" even"><span class="kw1"></div>




</span></li>




 	



<li class=" odd"></li>




 	



<li class=" even"><span class="kw1"><div</span> <span class="kw2">class</span><span class="kw1">=</span><span class="st0">"book-img"</span> <span class="kw2">ng-repeat-start</span><span class="kw1">=</span><span class="st0">"book in library"</span><span class="kw1">></span></li>




 	



<li class=" odd"><span class="kw1"><span</span><span class="kw1">></span><span class="">{{$index}}</span><span class="kw1"></span></span></li>




 	



<li class=" even"><span class="kw1"></div>




</span></li>




 	



<li class=" odd"></li>




 	



<li class=" even"><span class="kw1"><div</span> <span class="kw2">class</span><span class="kw1">=</span><span class="st0">"book-info"</span><span class=""> ng-repeat-end</span><span class="kw1">></span></li>




 	



<li class=" odd"><span class="kw1"><h4</span><span class="kw1">></span><span class="">{{book.name}}</span><span class="kw1"></h4>




</span></li>




 	



<li class=" even"><span class=""> {{book.blurb}}</span></li>




 	



<li class=" odd"><span class="kw1"></div>




</span></li>




</ol>




  Protractor gives a specific locator called by.repeater to help get elements from this list using index.

/ Returns the DIV for the second cat.
var secondCat = element(by.repeater('cat in pets').row(1));

// Returns the SPAN for the first cat's name.
var firstCatName = element(by.repeater('cat in pets').
    row(0).column('cat.name'));

// Returns a promise that resolves to an array of WebElements from a column
var ages = element.all(
    by.repeater('cat in pets').column('cat.age'));

// Returns a promise that resolves to an array of WebElements containing
// all top level elements repeated by the repeater. For 2 pets rows
// resolves to an array of 2 elements.
var rows = element.all(by.repeater('cat in pets'));

// Returns a promise that resolves to an array of WebElements containing
// all the elements with a binding to the book's name.
var divs = element.all(by.repeater('book in library').column('book.name'));

// Returns a promise that resolves to an array of WebElements containing
// the DIVs for the second book.
//You can give partial repeater text
var bookInfo = element.all(by.repeater('book').row(1));

// Returns the H4 for the first book's name.
var firstBookName = element(by.repeater('book in library').
    row(0).column('book.name'));

// Returns a promise that resolves to an array of WebElements containing
// all top level elements repeated by the repeater. For 2 books divs
// resolves to an array of 4 elements.
var divs = element.all(by.repeater('book in library'));



  This is an example given in the Protractor docs which clearly explains how the repeater locator can be used for finding the elements.   It is important to note that since the inception of Angular (post Angular 2) onwards, this locator cannot be used because the implementation of ng-repeat  has changed.  
  • How can I scroll down to bottom of a page using Protractor.

Ans : To scroll down to the bottom of a page – you can use a very large number in the Y coordinate in this method which is using the executeScript method from Protractor  
browser.executeScript('window.scrollTo(0,10000);').then(function () {
    expect(<some control>.<some state>).toBe(<some outcome>);
})
Credit to this answer on StackOverflow for this.  
  • I want to test if an element contains certain class. How can I do that with Protractor?

Ans :  The easiest way would be to use the getAttribute method in the Protractor API to achieve this like expect (element(by.css('some_css')).getAttribute('class').toMatch('ngPristine')); However, there is a caveat to the approach using toMatch() since it only does partial matching. So if you have ngDirty and ngPristine for an element in the DOM, it will return true. However, I found this answer on StackOverflow more conclusive, where we’re expecting only the exact matches. Credits to the author for this fantastic answer.  
  • How to use POM with Protractor. Can you give an example? or Have you implemented Page Object Model using Protractor.

Ans : The answer to this question depends on whether you have or have not implemented the Page Object Model or have modularised your test cases. In general, there are a lot of advantages of Page Object Model, so it seems quite necessary that for a mid level or a big project, POM is implemented with Protractor too. A general structure that I like to follow is to keep the locators , page methods and page implementation separate. So the directory structure looks clean and the maintenance becomes easy. A sample directory structure that I have followed in one of my projects is like



root_dir
- test_data
- locators
     - page1.locators.ts
     - page2.locators.ts
..

- page_methods
      - base_methods.ts
      - page1_methods.ts
      - page2_methods.ts
..
- page_implementation
      - page1.spec.ts
      - page2.spec.ts

- reports
      - reports.html
      - reports.json

- config
      - config.ts

  Let me know in comments if I should create a git with the examples.  
  • What is Control Flow in Protractor? How to enable/disable it?

Ans : In order to understand Control Flow, you need to understand that WebDriverJS and by that way Protractor actions are asynchronous. So in order to maintain consecutive actions, one after another , it maintains a chain of promises that are emptied one after another. This chain of promises is the Control Flow. Let’s see how it works. Let’s see this example,
it('should find an element by text input model', function() {
    browser.get('app/index.html#/form');

    var username = element(by.model('username'));
    username.clear();
    username.sendKeys('Jane Doe');

    var name = element(by.binding('username'));

    expect(name.getText()).toEqual('Jane Doe');

    // Point A
  });
  At Point A, the call to the get method is at the front of the queue , that is the Control flow queue. The call to the getText() method is at the back of the queue, behind the get method call. Protractor adapts Jasmine so that each spec automatically waits until the control flow is empty before exiting. Jasmine expectations are also adapted to understand promises. So you’ll see that expect(name.getText()).toEqual('Jane Doe') to execute only after the pending actions before it are finished.   With new changes in JavaScript specification, it has been decided that the Control Flow will be disabled in future. As of now you can use the SELENIUM_PROMISE_MANAGER manager flag in the conf.js file to enable/disable the Control Flow.  
  • How to use async/await in Protractor?

Ans : In order to use the async/await feature, you’ll have to disabled the promise manager first. So you need to do SELENIUM_PROMISE_MANAGER: false in the conf.js file and then in your tests you can do something like this

it('is a simple implementation of async', async()=>{

await (expect(something).toEqual(something));

})

 
  • Do you know how we can find child elements in Protractor. Please explain.

Ans : In order to find child elements, you can chain the locators to find the child element within a parent element. Let’s say I have to find an anchor tag inside an element with name=Karan, then it would be something like this element(by.name('Karan')).element(by.tagName('a')); If there is a need to find multiple elements inside a specific element, then we call use all to club the parent element with the child element locators, element(by.css('some-css')).all(by.tagName('some-tag')); Now you can also use the power of first/last/get with index to get a particular element

element.all(by.css('some-css')).first().element(by.tagName('tag-within-css'));
element.all(by.css('some-css')).get(index).element(by.tagName('tag-within-css'));
element.all(by.css('some-css')).first().all(by.tagName('tag-within-css'));

 
  • What is the difference between $ and $$ when using Protractor?

Ans : $ is nothing but the shortcut for the css locator. So this $('some-css') is same as element(by.css('some-css'))   Ans similarly, $$is same as element.all(by.css('some-css')). So $$is for css selectors when we want to find multiple elements while $ is for a single element.     This brings to the end of the second part of the series of Protractor interview questions. I will keep posting some more questions in this series. In the meantime, you can fill this questionnaire to let me know what tool should I cover next in this series of interview questions.