Closed juliemr closed 10 years ago
Exposing WebElement finders on the protractor instance like so would be nice. Also, in this happy future mocha/chai is supported.
describe('api/ng.$http', function() {
beforeEach(function() {
client.get('index-jq-nocache.html#!/api/ng.$http');
});
it('should make a JSONP request to angularjs.org', function() {
client.find.css(':button:contains("Sample JSONP")').click();
client.find.css(':button:contains("fetch")')).click();
client.find.binding('status').text().should.eventually.eql('200');
client.find.binding('data').text().should.eventually.match(/Super Hero!/);
});
});
Here's the design for this, based on the following goals:
Protractor will expose a limited set of global variables
protractor // the namespace, this contains everything available on the
// webdriver namespace such as Key and Button. This
// contains only static stuff. Backwards compatible.
browser // an instance of protractor, this wraps an instance of
// webdriver, can be used for navigation, getting the title
// and page source, etc.
element // function for element location, described below.
by // for element location, described below.
$ // an alias for element(by.css())
Protractor will expose a new type: enhanced element locators. This will be available via the element function.
element(by.<strategy>(<string>));
This element locator can either be used directly
browser.findElement(by.css('.foo')).getText();
or it can be used via one of the methods that enhanced element locators expose - these generally correspond to actions taken over the webdriver wire protocol.
element(by.css('.foo')).getText();
$('.foo').getText(); // equivalent.
Some helper functions will be added, such as a count() function for repeaters. This will be backwards compatible - you can still do
var ptor = protractor.getInstance();
ptor.findElement(protractor.By.css('.foo'));
in that case, ptor === browser
and protractor.By.css
is a subset of element(by.css)
.
A Page Object DSL could be created like this:
var TodoPage = function(element) {
// element locators - no call is made over the webdriver
// wire protocol by just defining these, only when
// they are used.
this.todoList = element(by.repeat('todo in todos'));
this.newTodo = element(by.model('todoText'));
this.addTodoButton = element(by.css('.btn-primary'));
this.addNewTodo = function(todo) {
this.newTodo.sendKeys(todo);
this.addTodoButton.click();
};
this.getLatestTodo = function() {
return this.todoList.row(0).getText();
};
}
Tests would look like:
todoPage = new TodoPage();
todoPage.addNewTodo('bake cookies');
expect(todoPage.getLatestTodo()).toMatch('cookie');
The underlying webdriver instance can be accessed with
browser.driver
A complicated action, e.g. something with an action sequence, would look like:
browser.actions().dragAndDrop(element, {x: 30, y: 0}).perform();
Sending a global key press would look like:
element(by.css('.body')).sendKeys(protractor.Key.ESCAPE);
Need a shorter syntax for finding elements, and a migration path from angular scenario tests.
Consider something like: