We are using the Page Object pattern to organize our internal AngularJS application tests.
Here is an example page object we have:
var LoginPage = function () {
this.username = element(by.id("username"));
this.password = element(by.id("password"));
this.loginButton = element(by.id("submit"));
}
module.exports = LoginPage;
In a single-browser test, it is quite clear how to use it:
var LoginPage = require("./../po/login.po.js");
describe("Login functionality", function () {
var scope = {};
beforeEach(function () {
browser.get("/#login");
scope.page = new LoginPage();
});
it("should successfully log in a user", function () {
scope.page.username.clear();
scope.page.username.sendKeys(login);
scope.page.password.sendKeys(password);
scope.page.loginButton.click();
// assert we are logged in
});
});
But, when it comes to a test when multiple browsers are instantiated and there is the need to switch between them in a single test, it is becoming unclear how to use the same page object with multiple browsers:
describe("Login functionality", function () {
var scope = {};
beforeEach(function () {
browser.get("/#login");
scope.page = new LoginPage();
});
it("should warn there is an opened session", function () {
scope.page.username.clear();
scope.page.username.sendKeys(login);
scope.page.password.sendKeys(password);
scope.page.loginButton.click();
// assert we are logged in
// fire up a different browser and log in
var browser2 = browser.forkNewDriverInstance();
// the problem is here - scope.page.username.clear() would be applied to the main "browser"
});
});
Problem:
After we forked a new browser, how can we use the same Page Object fields and functions, but applied to a newly instantiated browser (browser2
in this case)?
In other words, all element()
calls here would be applied to browser
, but needed to be applied to browser2
. How can we switch the context?
Thoughts:
one possible approach here would be to redefine the global
element = browser2.element
temporarily while being in the context ofbrowser2
. The problem with this approach is that we also havebrowser.wait()
calls inside the page object functions. This means thatbrowser = browser2
should be also set. In this case, we would need to remember thebrowser
global object in a temp variable and restore it once we switch back to the mainbrowser
context..another possible approach would be to pass the browser instance into the page object, something like:
var LoginPage = function (browserInstance) { browser = browserInstance ? browserInstance : browser; var element = browser.element; // ... }
but this would probably require to change every page object we have..
Hope the question is clear - let me know if it needs clarification.
Look at my solution. I simplified example, but we are using this approach in current project. My app has pages for both user permissions types, and i need to do some complex actions same time in both browsers. I hope this might show you some new, better way!