Writing end-to-end tests using Protractor

Loading

Protractor is an end-to-end testing framework specifically designed for Angular applications. It interacts with your application like a real user would, simulating user interactions such as clicking, typing, and navigation. Protractor is built on top of WebDriverJS, and it integrates with Jasmine for test assertions, which is commonly used in AngularJS applications.

This guide will walk you through setting up Protractor, writing basic end-to-end tests, and executing them for your AngularJS application.


1. Setting Up Protractor

Step 1: Install Protractor

To get started with Protractor, you need to install it along with the necessary dependencies. First, you need to install Node.js if it’s not already installed. Then, install Protractor globally using npm.

npm install -g protractor

This will install Protractor globally on your machine. You can verify the installation with the following command:

protractor --version

Step 2: Install WebDriver

Protractor requires WebDriver for interacting with browsers. You can install WebDriver using the following command:

webdriver-manager update

This command downloads the necessary binaries for different browsers (e.g., ChromeDriver, GeckoDriver for Firefox).

To start the WebDriver server, run:

webdriver-manager start

Now, Protractor will be able to control your browser for end-to-end testing.

Step 3: Configure Protractor

Create a configuration file for Protractor, typically named protractor.conf.js. This file defines how Protractor runs the tests, which browser to use, the test framework, and other settings.

Here’s an example protractor.conf.js:

exports.config = {
directConnect: true, // Direct connection to the browser without Selenium Server
capabilities: {
browserName: 'chrome' // You can use chrome or firefox here
},
framework: 'jasmine', // We use Jasmine for the test framework
specs: ['./tests/spec.js'], // Path to your test files
jasmineNodeOpts: {
defaultTimeoutInterval: 30000, // Time limit for each test
showColors: true, // Display results in color
},
onPrepare: function() {
// This can be used to configure any setup before tests run
browser.ignoreSynchronization = true; // Ignore AngularJS synchronization (if necessary)
}
};

This configuration file tells Protractor to use the Jasmine framework, the Chrome browser, and the path to the test files. The onPrepare function is useful for performing setup before tests run (e.g., adjusting AngularJS synchronization).


2. Writing Your First Protractor Test

Now that Protractor is set up, let’s write our first end-to-end test for an AngularJS application.

Step 1: Create a Test File

In the specs directory (or another folder), create a file called spec.js. This is where you’ll write your test scripts.

Step 2: Write a Basic Test

Here’s a simple test case that checks if the title of the AngularJS application is correct:

describe('AngularJS Application', function() {

// Navigate to the application's home page
it('should have the correct title', function() {
browser.get('http://localhost:8080'); // URL of the application

// Get the title of the page and verify it
expect(browser.getTitle()).toBe('My AngularJS App');
});
});

Step 3: Running the Test

Once your test is written, you can run it using the following command:

protractor protractor.conf.js

Protractor will:

  1. Launch the browser (Chrome, in this case).
  2. Navigate to http://localhost:8080 (your app’s URL).
  3. Check the title of the page and verify if it matches “My AngularJS App”.

3. Simulating User Interactions

Protractor allows you to simulate various user actions like clicking buttons, entering text in input fields, and more. Here’s an example of how to test a login form.

Step 1: Write a Test for a Form

Let’s assume the application has a login form with the following HTML:

<form name="loginForm">
<input type="text" ng-model="username" name="username" />
<input type="password" ng-model="password" name="password" />
<button ng-click="login()" type="submit">Login</button>
</form>

Here’s how to write a test for this form:

describe('Login Form', function() {
it('should submit the form when valid data is entered', function() {
// Open the login page
browser.get('http://localhost:8080/login');

// Fill in the username and password fields
element(by.model('username')).sendKeys('testuser');
element(by.model('password')).sendKeys('password123');

// Click the login button
element(by.buttonText('Login')).click();

// Wait for the next page to load and check the URL
browser.wait(protractor.ExpectedConditions.urlContains('/dashboard'), 5000);

// Verify that the URL contains '/dashboard'
expect(browser.getCurrentUrl()).toContain('/dashboard');
});
});

Step 2: Running the Test

After writing the test, run it with the following command:

protractor protractor.conf.js

In this test:

  1. element(by.model('username')): Locates the input field for the username using the AngularJS model binding.
  2. sendKeys(): Enters text into the input field.
  3. element(by.buttonText('Login')).click(): Clicks the login button.
  4. browser.wait(): Waits for the URL to contain /dashboard after login, ensuring the login was successful.
  5. expect(): Verifies that the current URL contains /dashboard.

4. Handling AngularJS Specific Features

AngularJS applications often include features like two-way data binding and routing, which can make tests a bit more complicated. Protractor provides a couple of options to handle Angular-specific features.

Handling Angular Synchronization

Protractor automatically waits for AngularJS to complete its tasks (e.g., updating the view, finishing an AJAX call). However, if you’re testing non-Angular pages or performing actions outside of Angular’s control, you may need to disable synchronization.

For non-Angular pages or when needed, set the ignoreSynchronization option to true:

browser.ignoreSynchronization = true;

This tells Protractor not to wait for AngularJS to finish before performing actions.

Handling Delays with ExpectedConditions

Protractor provides ExpectedConditions for waiting for certain conditions to be true, such as waiting for an element to be visible or clickable.

var EC = protractor.ExpectedConditions;
var loginButton = element(by.buttonText('Login'));

// Wait until the login button is clickable
browser.wait(EC.elementToBeClickable(loginButton), 5000);

// Click the login button
loginButton.click();

5. Using Protractor with Jasmine Assertions

Protractor uses Jasmine for its assertion framework. You can use all of Jasmine’s built-in matchers, like expect(), to assert conditions.

  • expect(element.isPresent()).toBe(true): Verifies that an element is present in the DOM.
  • expect(element.getText()).toEqual('Expected Text'): Verifies that the text of an element matches the expected text.
  • expect(browser.getCurrentUrl()).toContain('some/path'): Verifies that the current URL contains a specific string.

6. Debugging Tests

Sometimes your tests may not behave as expected. Here are a few strategies for debugging:

  • Add a browser.sleep(): Temporarily pause the test to inspect the page manually. browser.sleep(3000); // Wait for 3 seconds
  • Use console.log(): Print out values in your test for inspection.
  • Protractor Debugging: Run Protractor with the --debug flag to step through your test in the Node.js debugger.

7. Running Tests in Continuous Integration

For CI (Continuous Integration) pipelines, you can run Protractor tests in headless mode (without opening a browser window) using tools like Chrome in headless mode or using a service like Sauce Labs for cloud testing.

Add the following to your protractor.conf.js for headless testing:

capabilities: {
browserName: 'chrome',
chromeOptions: {
args: ['--headless', '--disable-gpu', '--window-size=800x600']
}
}

Leave a Reply

Your email address will not be published. Required fields are marked *