The basic problem is here is that I was trying to login initially, launch my app, then run ALL specs. It turned out to NOT be a good approach.
What I couldn't figure out is the following:
Why navpanel-spec.js
below was running first - before the login and launch js files. In other words, if I add a browser.pause() in navpanel-spec.js, it pauses immediately - PRIOR to even running my login-spec.js code. CONFUSING !
In my Protractor.config.js file I have a few specs :
specs: [
'spec/login.js',
'spec/launch-awesome-app.js',
'spec/navpanel-spec.js',
'spec/another-spec.js',
'spec/yet-another-spec.js'
]
login.js
and launch-awesome-app.js
work fine. They log into the menu system, then click thru the menus in order to launch myAwesomeapp
- no problem.
BUT, I'm having issues launching these files sequentially. Something to do with the Selenium Control-flow I assume, as it appears to be parsing all spec files and executing any browser.
commands immediately.
I'm looking for a solution, or perhaps a better approach to :
1) Logging into the menu framework
2) Clicking thru the menus to launch the the appropriate URL
3) And finally running the spec.js files which target the URL in step 2
Here's my original navpanel-spec.js
version:
describe('Testing My Awesome App', function () {
var panelObj = new PanelObjects();
var urlDefault = 'https://server/apps/Default.aspx?r=1';
var urlApp = 'https://server/apps/MyAwesomeApp.html';
browser.get(urlApp); // Runs my AwesomeApp tests okay, HOWEVER it launches a new browser window.
browser.get(urlDefault); // Launches app framework with top nav menus and embedded <iframe>,
// HOWEVER I cannot select iframe and successfully run tests here.
beforeEach(function () {
browser.sleep(5000);
browser.waitForAngular();
});
// USE-CASE OBJECT !!
var items = browser.params.useCaseJsonFile["navigatePanels"];
browser.getAllWindowHandles().then(function (handles) {
handles.map(function (win, idx) {
browser.driver.getCurrentUrl().then(function (curr) {
if (curr.indexOf('Default.aspx') >= 0) {
browser.driver.switchTo().window(handles[idx]);
}
});
});
});
browser.switchTo().frame(element(by.id('1')).getWebElement());
var testId = element(by.id('middle'));
console.log(testId);
items.map(function (item) {
if (item.enableTest) {
var specItem = it(item.name, function () {
console.log('------------------------------');
console.log('---- ' + item.describe);
browser.waitForAngular();
// select panels, etc..
panelObj.panelClick(item.panelName).then(function () {
// ...
});
panelObj.getPanelText(item.panelName).then(function (title) {
expect(title).toContain(item.panelTitle);
});
});
}
});
});
UPDATE: After much discussion, I moved my login
and launch
logic into a page objects file. And now I call login/launch at the beginning of each, independent test spec.
Here's my updated navpanel-spec.js
test:
var LoginObjects = require('../pageObjects/login-objects.js');
describe('Testing My Awesome App', function () {
var panelObj = new PanelObjects();
var loginObj = new LoginObjects();
//var urlDefault = 'https://server/apps/Default.aspx?r=1';
//browser.get(urlApp); // USING PAGE OBJECTS NOW...
browser.ignoreSynchronization = true;
// LOGIN AND LAUNCH APP !!!
loginObj.Login();
loginObj.Launch();
beforeEach(function () {
browser.sleep(5000);
browser.waitForAngular();
});
// USE-CASE OBJECT !!
var items = browser.params.useCaseJsonFile["navigatePanels"];
// SWITCH TO iframe ELEMENT
loginObj.switchWindowAndFrame();
items.map(function (item) {
if (item.enableTest) {
var specItem = it(item.name, function () {
console.log('------------------------------');
console.log('---- ' + item.describe);
browser.waitForAngular();
// select panels, etc..
panelObj.panelClick(item.panelName).then(function () {
// ...
});
panelObj.getPanelText(item.panelName).then(function (title) {
expect(title).toContain(item.panelTitle);
});
});
}
});
});
and my page objects :
module.exports = function(){
this.Login = function(){
var url = browser.params.loginUrl;
browser.driver.get(url);
browser.sleep(200);
var userName = browser.params.credential.userId;
var password = browser.params.credential.password;
element(by.id('username')).clear().then(function(){
element(by.id('username')).sendKeys(userName);
element(by.id('password')).sendKeys(password);
});
browser.sleep(1000);
var that = this;
var submitElement = element(by.id('bthLogin'));
submitElement.click().then(function () {
browser.getAllWindowHandles().then(function (handles) {
// LOGIN MESSAGE WINDOW
browser.driver.getCurrentUrl().then(function(curr){
if (curr.indexOf('LoginMsg.aspx') >= 0){
// Do we really need to close the login successful browser ???
browser.driver.close();
}
});
browser.driver.switchTo().window(handles[1]);
});
});
},
this.Launch = function(){
var sel = '#TheMenu1 > ul > li:first-child';
var elem = element(by.css(sel));
elem.click().then(function(){
browser.sleep(1000);
var elem2 = element(by.cssContainingText('.rmLink', 'The First Menu Item'));
elem2.click();
// Select menu item; sleep before attempting to click().
var subElem = element(by.cssContainingText('.rmLink', 'My Awesome App'));
browser.sleep(1000);
subElem.click();
browser.waitForAngular();
});
},
this.switchWindowAndFrame = function(){
browser.getAllWindowHandles().then(function (handles) {
handles.map(function(win, idx){
browser.driver.getCurrentUrl().then(function(curr){
if (curr.indexOf('Default.aspx') >= 0){
browser.driver.switchTo().window(handles[idx]);
}
});
});
});
browser.switchTo().frame(element(by.css('[name="1"]')).getWebElement());
}
};
I think you are doing this wrong your specs should not depend on each other. The idea of specs is that you can run them parallel and independent from each other.
In my projects I use a login function that I call from the tests that require it (I only login once in each spec) inside the beforeAll() method.
So I think that if your specs all depend on the result of the previous one you should either join them or find a way to make them independent.
Good Luck!