Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Syntax reboot #156

Closed
juliemr opened this issue Oct 10, 2013 · 2 comments
Closed

Syntax reboot #156

juliemr opened this issue Oct 10, 2013 · 2 comments
Assignees
Milestone

Comments

@juliemr
Copy link
Member

juliemr commented Oct 10, 2013

Need a shorter syntax for finding elements, and a migration path from angular scenario tests.

Consider something like:

describe("api/ng.$http", function() {
  beforeEach(function() {
    ptor.get("index-jq-nocache.html#!/api/ng.$http");
  });

  it('should make a JSONP request to angularjs.org', function() {
    webelem.by.css(':button:contains("Sample JSONP")').click();
    webelem.by.css(':button:contains("fetch")')).click();
    expect(webelem.by.binding('status').getText()).toBe('200');
    expect(webelem.by.binding('data').getText()).toMatch(/Super Hero!/);
  });
});

// The protractor runner would expose some additional things to the global
// namespace. It could now be:
// - all the Jasmine scaffolding (describe, it, expect, matchers).
// - protractor, the protractor namespace.
// - ptor, an instance of protractor.
// - element, providing utilities to find WebElements.
// - elements, find multiple elements.
@ghost ghost assigned juliemr Oct 10, 2013
@sidwood
Copy link

sidwood commented Oct 16, 2013

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!/);
  });
});

@juliemr
Copy link
Member Author

juliemr commented Oct 25, 2013

Here's the design for this, based on the following goals:

  • feels natural, easy for those writing tests
  • not too much typing!
  • seamless access to the underlying webdriver functions
  • extensible using a PageObject like DSL
  • clear mapping to the actions being taken over the WebDriver wire protocol

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);

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants