In this second part of the Protractor for Beginners tutorial, we will cover two tasks. The first task will recap what you learnt in Task 1.1 with a bit more information about the matchers isDisplayed and isPresent, and the second task will cover some new things: how to enter text, and the jasmine matchers toEqual and toContain.

Remember if you get stuck at all to use the example code here.

Task 1.2: Describe “Download button should open up a download modal”

In Task 1.1 you learnt how to use the isDisplayed matcher, so in this second task you will be using it alongside the matcher isPresent. You will be checking that the download button modal is present as well as displayed, and the differences between the two.

  1. Open up the angularjs.org site.
  2. When the download modal is open, right click on the modal and inspect the element. Hover over the different levels of divs until the full modal is highlighted (hover over classname = “modal fade download-modal in” ).
  3. Using the class download-modal, create a variable called DownloadModal and within it create a page object for the download modal:
    
                var DownloadModal = function() {
                    this.downloadModal = element(by.css(".download-modal"));
                }
            
  4. Create a new describe suite and it spec:
    
                describe('Download button', function() {
    
                    beforeEach(function() {
                                browser.get('https://angularjs.org/');
                    });
    
                    it('should open up a download modal', function() {
    
                    });
                });
            
  5. Within the describe, call the homePage and downloadModal variables (homePage = new HomePage(); etc )
  6. For this test, we need to prove that the modal is non-existent before the button is pressed, and is visible after it is pressed. To do this we need to use isPresent when the modal is not visible. This is because when an item is not present in the DOM or present on the page, isDisplayed will throw an exception error.
  7. In the it create an expect to show that the download modal is not present in the DOM: expect(downloadModal.downloadModal.isPresent()).toBe(false);
  8. Underneath this, tell protractor to click on the download button by using .click: homePage.downloadButton.click();
  9. After the click, create an expect to show that download modal is now present both in the DOM and on the screen: expect(downloadModal.downloadModal.isDisplayed()).toBe(true);
  10. Run the test.
  11. Did both pass? If not, check the code is correct here:
    
                describe('Download button', function() {
                    var homePage = new HomePage();
                    var downloadModal = new DownloadModal();
    
                    beforeEach(function() {
                        browser.get('https://angularjs.org/');
                    });
    
                    it('should open up a download modal', function() {
                        expect(downloadModal.downloadModal.isPresent()).toBe(false);
                        homePage.downloadButton.click();
                        expect(downloadModal.downloadModal.isDisplayed()).toBe(true);
                    });
                });
            

Note: Remember to double check that the opposites also fail, to ensure you aren’t getting an false positives: expect(downloadModal.downloadModal.isPresent()).toBe(true) before the .click and expect(downloadModal.downloadModal.isDisplayed()).toBe(false); after the .click.

Now we want to see how isDisplayed differs from isPesent:

  1. In the it function, create an expect for isDisplayed to be false underneath expect(downloadModal.downloadModal.isPresent()).toBe(false).
  2. Run the test.
  3. Observe an error appears in the console, which says "No element found using...". This happens because the download modal doesn't appear in the DOM until it is selected and opened, so the matcher isDisplayed cannot find the element, causing it to throw an unsightly error.

What have you learnt from this task?

  • How to use the .click method.
  • The difference between isDisplayed and isPresent and when to use them.

Task 1.3: Describe "In The Basics tutorial, entering a name should output 'Hello [name]'"

In this task we will be looking at ‘The Basics’ section of the angularjs.org page. Scroll down to it and have a play about with it to get an idea of what it involves. For this task we will be inputting a name in to the Name field, and checking that the output after ‘Hello’ is correct. To do this we can use the matchers toEqual and toContain. There is a small difference between toEqual and toContain. toEqual is a matcher that compares the values exactly. For example, using toEqual to compare “hell” to “hello” would fail, but comparing “hello” and “hello” would pass. toContain is a matcher that compares the values and passes if the compared value simply contains part of the expected value. For example, comparing “hell” to “hello” would pass since “hell” is a part of “hello”.

  1. Right click on the part of the page surrounding The Basics and select ‘Inspect element’. Navigate through the divs until you find the one that highlights the entire ‘The Basics’ section of the page.
  2. The code for The Basics section is class="row example" , so type in to the console $(‘.row.example’) and press enter. Observe multiple elements with the name row example appear, but you only need the first one.
  3. Right click on the Name field, and select ‘Inspect element’. The highlighted HTML code says that the Name field is ng-model="yourName"
  4. Right click on the ‘Hello !’ text. The highlighted HTML code says that the Hello ! text is class=ng-binding, however there will be many many ng-bindings on the page. Double check this by typing $(‘.ng-binding’) in to the console and pressing Enter. So we will use the tag h1 by using element.tagName(“h1”).
  5. Using the model and class locators, create a page object for The Basics:
    
                var TheBasics = function() {
    
                    this.helloBox = element.all(by.css(".row.example")).get(0);
                    this.nameField = this.helloBox.element(by.model("yourName"));
                    this.helloOutput = this.helloBox.element(by.tagName("h1"));
                }
            
  6. In your spec file, disable the other describe suites by putting an ‘x’ in front of them: xdescribe. You can also disable individual specs by putting an ‘x’ in front of them: xit. Putting an x in front of the other describe suites will stop those suites from running whilst you might only want one to run.
  7. Create the describe suite and the it spec for this test:
    
                describe('In "The Basics" tutorial', function() {
                    var homePage = new HomePage();
                    var theBasics = new TheBasics();
    
                    beforeEach(function() {
                        browser.get('https://angularjs.org/');
                    });
    
                    it('entering a name should output "Hello Name"', function() {
    
                    });
                });
            
  8. First thing you want to do in the it spec is send keys to the name field. Do this using the sendKeys method and use your own name as a string:
    
                theBasics.nameField.click();
                theBasics.nameField.sendKeys('yourname');
            
  9. Run the test. Watch the test run and observe “Hello yourname!” appears in the output box.
  10. Now you want to check that ‘yourname’ appears in the text using the method .getText:
    
                expect(theBasics.helloOutput.getText()).toContain('yourname');
            
  11. Run the test and it should pass! If it doesn't, check your code against this:
  12. 
                theBasics.nameField.click();
                theBasics.nameField.sendKeys('yourname');
                expect(theBasics.helloOutput.getText()).toContain('yourname');
            
  13. Use toEqual to create the next test:
    
                expect(theBasics.helloOutput.getText()).toEqual('Hello yourname!');
            
  14. Run the test to see if it passes!
  15. It is good practice to place things like strings or numbers in their own variables. If something is hardcoded in but needs changing later on, and especially if it will be used multiple times, it takes much more effort to change them all individually. Creating variables to contain these at the top of each test (or even in page objects depending where they are needed) instead of hardcoding them can save a lot of headache later on.
  16. Create a variable called name, and make it equal to a string of your name:
    
                var name = 'yourname';
                theBasics.nameField.click();
                theBasics.nameField.sendKeys(name);
                expect(theBasics.helloOutput.getText()).toContain(name);
                expect(theBasics.helloOutput.getText()).toEqual('Hello' + ' ' + name + '!');
            
  17. Place it all together:
    
                describe('In "The Basics" tutorial', function() {
                    var homePage = new HomePage();
                    var theBasics = new TheBasics();
    
                    beforeEach(function() {
                        browser.get('https://angularjs.org/');
                    });
    
                    it('entering a name should output "Hello Name"', function() {
                        var name = 'yourname';
    
                        theBasics.nameField.click();
                        theBasics.nameField.sendKeys('yourname');
    
                        expect(theBasics.helloOutput.getText()).toEqual('Hello yourname!');
                        expect(theBasics.helloOutput.getText()).toContain('yourname');
    
                        theBasics.nameField.click();
                        theBasics.nameField.sendKeys(name);
                        expect(theBasics.helloOutput.getText()).toContain(name);
                        expect(theBasics.helloOutput.getText()).toEqual('Hello' + ' ' + name + '!');
                    });
                });
            
  18. Run this to ensure it passes. You can now play around with different combinations of strings and matchers to create your own tests.

What have you learnt from this task?

  • The different between toEqual and toContain
  • Practicing using the sendKeys method
  • Touched on some good practices when working with hardcoded strings. Variables are your friend!

In the next tutorial we will be using getText a bit more, and we will cover how to use .count to find the number of items in a list.