What is protractor?
Protractor is an end-to-end test framework for Angular and AngularJS applications. It runs tests against your application running in a real browser, interacting with it as a user would.
What are protractor's main functionalities?
End-to-End Testing
Protractor allows you to write end-to-end tests for your Angular applications. The code sample demonstrates navigating to an AngularJS website, selecting elements, and making assertions about their state.
const { browser, element, by } = require('protractor');
browser.get('http://www.angularjs.org');
const todoList = element.all(by.repeater('todo in todoList.todos'));
expect(todoList.count()).toEqual(2);
expect(todoList.get(1).getText()).toEqual('build an AngularJS app');
Automatic Waiting
Protractor automatically waits for Angular to finish rendering and for any outstanding $http calls to be completed before performing the next action. This reduces the need for explicit waits in your tests.
const { browser, element, by } = require('protractor');
browser.get('http://www.angularjs.org');
const addButton = element(by.css('[value="add"]'));
addButton.click();
const todoList = element.all(by.repeater('todo in todoList.todos'));
expect(todoList.count()).toEqual(3);
Integration with Jasmine
Protractor integrates seamlessly with the Jasmine testing framework, allowing you to write tests in a behavior-driven development (BDD) style. The code sample shows a Jasmine test suite that adds a new todo item and verifies its presence.
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get('http://www.angularjs.org');
element(by.model('todoList.todoText')).sendKeys('write a protractor test');
element(by.css('[value="add"]')).click();
const todoList = element.all(by.repeater('todo in todoList.todos'));
expect(todoList.count()).toEqual(3);
expect(todoList.get(2).getText()).toEqual('write a protractor test');
});
});
Other packages similar to protractor
cypress
Cypress is a next-generation front-end testing tool built for the modern web. It offers a more developer-friendly experience with features like time travel, real-time reloads, and automatic waiting. Unlike Protractor, Cypress does not require WebDriver and runs directly in the browser.
webdriverio
WebdriverIO is a popular testing framework that allows you to run tests based on the WebDriver protocol and Appium. It supports both synchronous and asynchronous commands and can be used for both web and mobile applications. WebdriverIO is more versatile compared to Protractor, which is specifically designed for Angular applications.
testcafe
TestCafe is a Node.js tool to automate end-to-end web testing. It works without WebDriver and is compatible with any modern web application. TestCafe provides a simple syntax and powerful features like parallel test execution and easy integration with CI/CD pipelines. Unlike Protractor, TestCafe is framework-agnostic and can be used with any web application.
Protractor
Protractor is an end-to-end test framework for AngularJS applications. Protractor is a Node.js program built on top of WebDriverJS. Protractor runs tests against your application running in a real browser, interacting with it as a user would.
Compatibility
Protractor 4 is compatible with nodejs v4 and newer. If you absolutely need to use nodejs at 0.12, use Protractor@2.
Protractor works with Angular versions greater than 1.0.6/1.1.4, and is compatible with Angular 2 applications. Note that for Angular 2 apps, the binding
and model
locators are not supported. We recommend using by.css
.
Getting Started
The Protractor documentation for users is located in the protractor/docs folder.
To get set up and running quickly:
Once you are familiar with the tutorial, you’re ready to move on. To modify your environment, see the Protractor Setup docs. To start writing tests, see the Protractor Tests docs.
To better understand how Protractor works with the Selenium WebDriver and Selenium Server see the reference materials.
Getting Help
Check the Protractor FAQ and read through the Top 20 questions on StackOverflow.
Please ask usage and debugging questions on StackOverflow (use the "protractor" tag), the Gitter chat room, or in the Angular discussion group. (Please do not ask support questions here on Github.)
For Contributors
Clone the github repository:
git clone https://github.com/angular/protractor.git
cd protractor
npm install
./bin/webdriver-manager update
cd website
npm install
cd ..
Start up a selenium server. By default, the tests expect the selenium server to be running at http://localhost:4444/wd/hub
. A selenium server can be started with webdriver-manager which is included in
bin/webdriver-manager.
webdriver-manager update
webdriver-manager start
Protractor's test suite runs against the included test application.
Install the test application dependencies with:
npm run install_testapp
Start that up with
npm start
Then run the tests with
npm test
5.0.0
This version includes big changes around upgrading to selenium-webdriver 3.0.x.
See the selenium-webdriver changelog.
For the 5.0.0 release, we are still using the selenium standalone server 2.53.1
and recommend using Firefox 47. Firefox 48+ currently is not supported.
Breaking Changes
-
Minimum node version is now 6.9.x.
-
When testing with Firefox 47, use the capability option marionette: false
to use the legacy Firefox driver.
Before:
capabilities: {
browserName: 'firefox'
}
After:
capabilities: {
browserName: 'firefox',
marionette: false
}
-
We moved @types/jasmine
to a devDependency. This means that Jasmine
TypeScript users will need to include the @types/jasmine
as a project
dependency. This is to avoid conflicts for users that prefer mocha typings.
After:
"dependencies": {
"@types/jasmine": "^2.5.38"
}
-
Selenium-webdriver methods removed: WebDriver.prototype.isElementPresent
,
WebElement.prototype.getRawId
, WebElement.prototype.getInnerHtml
, and
WebElement.prototype.getOuterHtml
.
Before:
let isPresent = browser.driver.isElementPresent(By.tagName('a'));
let i = element(locator).getInnerHtml();
let o = element(locator).getOuterHtml();
After:
let isPresent = element(By.tagName('a')).isPresent();
let i = browser.executeScript("return arguments[0].innerHTML;", element(locator));
let o = browser.executeScript("return arguments[0].outerHTML;", element(locator));
-
Selenium-webdriver ErrorCodes
have been removed.
-
Adding cookies have been changed:
Before:
browser.manage().addCookie('testcookie', 'Jane-1234');
After:
browser.manage().addCookie({name:'testcookie', value: 'Jane-1234'});
-
Removed protractor.wrapDriver()
.
-
You can no longer use repl
command from within browser.pause()
. Instead,
use browser.explore()
to directly enter the repl
.
-
Sending flags that are not recognized by the CLI throws an error. Since flags
are a subset of all configuration options, these errors can be silenced with
--disableChecks
.
-
Auto-detection of the root element. This is a breaking change because it
changes the default root element behavior and removes the
config.useAllAngular2AppRoots
flag. Modern angular apps now
default to using all app hooks, and ng1 apps now check several places, notably
the element the app bootstraps to.
-
sauceProxy
configuration field has been removed. Use webDriverProxy
instead.
Before:
sauceProxy: 'http://sauceProxy'
After:
webDriverProxy: 'http://sauceProxy'
Features
-
(ec93c4a)
chore(cli): breaking change throw errors on unknown flags (#3921)
Unknown flags are options sent that is unrecognized by the CLI. For users that
encounter this error but would like to silence it, use: --disableChecks
.
closes #3216
-
(bc58332)
feat(rootEl): breaking change auto-detect the root element better (#3928)
This is a breaking change because it changes the default root element behavior
and removes the config.useAllAngular2AppRoots
flag. Modern angular apps now
default to using all app hooks, and ng1 apps now check several places, notably
the element the app bootstraps to.
closes #1742
-
(604fdbf)
cleanup(config): breaking change Remove redundant sauceProxy config (#3868)
Removes the sauceProxy
config field, and uses webDriverProxy
when creating
the SauceLabs client.
-
(9465b9f)
feat(mobile): add extended wd commands for appium (#3860)
Also had to make some minor changes to the website to handle longer inheritance
chains
Closes https://github.com/angular/protractor/issues/1940
-
(0e26b21)
feat(blockingproxy): Add synchronization with BlockingProxy. (#3813)
This adds support for BlockingProxy behind the flag --useBlockingProxy.
If set, the driver providers will start a proxy during their setup phase,
passing the selenium address to the proxy and starting a webdriver client
that talks to the proxy.
Starting a proxy for each driver provider isn't strictly necessary. However,
when we run with multiple capabilities it's easier to handle the logging if
each Protractor instance has it's own proxy.
Known issues:
- Doesn't work with directConnect. You can get the address of chromedriver by
mucking around in Selenium internals, but this probably changed for Selenium
3.0 and I doubt it's worth figuring out until we upgrade.
- Doesn't yet work with webDriverProxy (but it's an easy fix)
-
(ca4f1ac)
chore(driverProviders): add warnings to extra driver provider parameters (#3873)
- builds the driver provider in lib/driverProviders/index instead of lib/runner
closes #1945
-
(681b54a)
refactor(browser): Remove protractor.wrapDriver() breaking change (#3827)
Before:
Users could create their own selenium driver instance and enable Protractor on
it like so:
let capabilities = webdriver.Capabilities.chrome();
let driver = new webdriver.Builder().usingServer(seleniumAddress)
.withCapabilities(capabilities).build();
let browser = protractor.wrapDriver(driver);
Over the years, wrapDriver() has become increasingly broken as Protractor
needs extra configuration options that wrapDriver() doesn't set.
After:
This method is removed. If users need a new browser instance, they can
use browser.forkNewDriverInstance()
.
-
(86fd569)
feat(ngUpgrade): Auto detect ngUpgrade apps and make the ng12Hybrid flag
unnecessary for most users (#3847)
Bug fixes
-
(de153e7)
fix(launcher): running getMultiCapabilities should reject on errors (#3876)
closes #3875
-
(1345137)
fix(isElementPresent): for un-wrapped WebElement
s, browser.isElementPresent
was broken (#3871)
Closes #3864
-
(4af3b2e)
fix(element): Fix typing of ElementFinder.then (#3835)
Type then
as optional on ElementFinder.
Dependencies
-
(4d87c9c)
deps(update): update tslint and @types/selenium-webdriver (#3941)
- use @types/selenium-webdriver ~2.53.39
- fix for tslint
closes #3939
-
(7376708)
deps(tslint): set tslint to ~4.2 (#3938)
-
(cb38ed0)
Refactor element explorer to work with selenium-webdriver 3 (#3828)
This implementation now relies mostly on promises explicitly, so the control
flow is only used to add one large task to the queue. This should pave the way
for the eventual removal of the control flow, as well as getting element
explorer to work immediately.
BREAKING CHANGE
You can no longer use the repl
command from within browser.pause()
. Instead,
use browser.explore()
to directly enter the repl.
-
(8196059)
chore(dependency): switch to webdriver-manager 11.1.0 and remove
--versions.chrome 2.26
from circle.yml (#3865)
-
(397bf65)
deps(update): move @types/jasmine to devDependencies (#3795)
- update outdated dependencies
- move @types/jasmine to devDependencies
closes #3792
-
(a3e8b43)
deps(selenium-webdriver): upgrade to selenium 3 (#3781)
Please see the selenium-webdriver changelog
-
Removed method WebDriver.prototype.isElementPresent
-
Removed method WebElement.prototype.getRawId
-
Removed getInnerHtml
and getOutterHtml
-
Dependency required for upgrade: use jasminewd2@0.1.0
.
-
Selenium-webdriver requires node version 6+, updating travis and circle yml
to use node 6 and 7.
-
Use instanceof
selenium-webdriver error instead of error code.
Selenium-webdriver error codes have been deprecated.
-
Use executor with selenium-webdriver from lib/http
. Deferred executor has
been deprecated.
-
Fix quitting driverProviders
. When calling webdriver.quit
, the control
flow is shutdown and will throw an error.
-
Driver provider for direct connect has been modified to use ServiceBuilder
and to call the Service
to createSession
-
Note: Since this upgrade is still using FF 47, direct connect for Firefox is
required to pass "marionette: false" in the capabilities. If you do not pass
marionette to false, it will look for gecko driver in the PATH.
-
Added a TODO to support FF after 48+ with direct connect and gecko driver.
-
Updated browser.manage().addCookie('testcookie', 'Jane-1234');
to use
browser.manage().addCookie({name:'testcookie', value: 'Jane-1234'});
-
Updated debug commons for breakpoint updated to selenium-webdriver
lib/http
line 432.
-
For mocha tests, selenium-webdriver/testing
uses the global it
and
cannot be reassigned as Protractor's global it
. Some code has been
copied / modified to lib/frameworks/mocha
to make this work.
-
Capabilities for Firefox 47 requires setting marionette to false.
-
Setup still requires selenium standalone server 2.53.1 for Firefox tests.
Firefox version used is 47.
-
Using selenium standalone server 3, with Firefox 48+ tests fail with gecko
driver still do not work.
-
Selenium standalone 3 + FF 49 + gecko driver 0.11.1 does not work
-
Selenium standalone 3 + FF 48 + gecko driver 0.11.1 appears to work for a
single test but after it quits, selenium standalone no longer works with
firefox. When firefox 48 exists, logs show the following:
20:01:14.814 INFO - Executing: [delete session: e353fa1b-e266-4ec3-afb3-88f11a82473a])
[GFX1-]: Receive IPC close with reason=AbnormalShutdown
[Child 30665] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2052
[Child 30665] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2052
-
(eb31c9c)
deps(types): update @types/selenium-webdriver dependency (#3886)
Fixes issue #3879 and adds the protractor.Key.chord method