How to run an ordered test - angularjs

I want to
fill out name and password input fields
click login button
wait for page to load
click a button
How can I accomplish this? I realize promises are going to be involved. This is what I have tried:
conf.js
var env = require('./environment.js');
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['test/e2e/app/test-spec.js'],
baseUrl: env.baseUrl,
onPrepare: function() {
console.log("base url is: " + env.baseUrl);
browser.driver.get(env.baseUrl + '#/login');
element(by.model('my.username')).sendKeys('username');
element(by.model('my.password')).sendKeys('password');
console.log("clicking login button...");
element(by.css('button.md-primary.md-button.md-default-theme')).click();
// Login takes some time, so wait until it's done.
// For the test app's login, we know it's done when it redirects to
// /#/home.html.
browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
console.log("read current url as" + url);
console.log("returning...");
return /\/#\/home\//.test(url);
});
}, 10000);
}
};
Then a test.
test-spec.js
describe('Click button on home page', function() {
it('should click the button', function() {
console.log("looking for button on home page")
element(by.css('button.md-fab.md-accent.md-primary.md-button.md-default-theme')).click();
});
});
And for reference
environment.js
// Common configuration files with defaults plus overrides from environment vars
var webServerDefaultPort = 9002;
module.exports = {
// The address of a running selenium server.
seleniumAddress:
(process.env.SELENIUM_URL || 'http://localhost:4444/wd/hub'),
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName':
(process.env.TEST_BROWSER_NAME || 'chrome'),
'version':
(process.env.TEST_BROWSER_VERSION || 'ANY')
},
// Default http port to host the web server
webServerDefaultPort: webServerDefaultPort,
// A base URL for your application under test.
baseUrl:
'http://' + (process.env.HTTP_HOST || 'localhost') +
':' + (process.env.HTTP_PORT || webServerDefaultPort)
};
Outputs
Using the selenium server at http://localhost:4444/wd/hub
[launcher] Running 1 instances of WebDriver
base url is: http://localhost:9002
clicking login button...
looking for button on home page
I never see "read current url as" which tells me the promise is not executing and my test executes too early.
So the Error I get makes sense because the test ran too early:
NoSuchElementError: No element found using locator: By.cssSelector("button.md-> fab.md-accent.md-primary.md-button.md-default-theme")

Put the wait() call into beforeEach():
describe('Click button on home page', function() {
beforeEach(function () {
browser.wait(function() {
return browser.getCurrentUrl().then(function(url) {
console.log("read current url as" + url);
console.log("returning...");
return /\/#\/home\//.test(url);
});
}, 10000);
});
it('should click the button', function() {
console.log("looking for button on home page")
element(by.css('button.md-fab.md-accent.md-primary.md-button.md-default-theme')).click();
});
});
Or, you can wait for the element on the home page to become visible:
describe('Click button on home page', function() {
var scope = {};
beforeEach(function () {
var EC = protractor.ExpectedConditions;
scope.defaultTheme = element(by.css('button.md-fab.md-accent.md-primary.md-button.md-default-theme'));
browser.wait(EC.visibilityOf(scope.defaultTheme), 10000);
});
it('should click the button', function() {
console.log("looking for button on home page");
scope.defaultTheme.click();
});
});

After tinkering around I had the most success with the following setup:
beforeAll() used to login
sendkeys() failed to function for me inside of OnPrepare(). I shortened OnPrepare() down to a simple redirect to login page.
I set config.js to use firefox because I had problems getting click() to function in chrome.
Use Jasmine2 (jasmine1 is default)
Use a series of browser.wait to workout the timing. You can wait for an element to exist (one that only exists on page2 per-se)
browser.waitForAngular() performs similar duties. I had less success with this feature
Protractor configuration file documentation
test-spec.js
describe('Click button on home page', function() {
beforeAll(function () {
element(by.model('my.username')).sendKeys('username');
element(by.model('my.password')).sendKeys('password');
element(by.id('loginButton')).click();
browser.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
var result = url.indexOf("/#/home") > -1;//wait for url to change to this
return result;
});
}, 10000);
});
it('should click the button', function() {
console.log("executing test...");
browser.ignoreSynchronization = true;//Yea I had to use this here too...I dunno why this is required
element(by.id('someButton')).click();
browser.wait(function() {
console.log('inside wait for vm.firstName');
return browser.isElementPresent(by.model('vm.firstName'));
}, 10000).then(function(){
//rinse and repeat with more waits as pages change
});
expect(true).toBe(true);
});
});
conf.js
var env = require('./environment.js');
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['test/e2e/app/test-spec.js'],
baseUrl: env.baseUrl,
capabilities: {
browserName: 'firefox'
},
framework: 'jasmine2',
onPrepare: function() {
browser.driver.get(env.baseUrl + '#/login');
}
};
environment.js
no change

Related

Page reloading for every "it" statement in protractor and printing "."

Have anyone found fix for this. I am new to protractor and got some script running. I have a login page and once logged in search for a user. My spec.js has the following structure.
describe('Smoke', function() {
//sum stuff
beforeEach(function () {
browser.get('https://login/');
});
it('should have a title', function() {
expect(browser.getTitle()).toEqual('title');
browser.pause()
});
it('and Login to MSIX', function () {
login.login(username);
});
it('search for a user', function () {
searchUser.searchForUser();
});
it ('print test result', function () {
var userN = loginName.getText().then((text) => {
return text;
})
// at this point data is still a managed promise!
userN.then((text) => {
console.log("Logged in user is: "+text);
console.log("User " +username+" logged in successfully"); // your text would be printed!
})
})
});
For every "it" statement the page reloads and I am losing the content on the page. Also if you notice the last "it" statement to print test result I am noticing "." before the output in console
**..**[12:55:55] W/element - more than one element found for locator by.model("query.identifier") - the first result will be used
**.**Logged in user is: sample user
User abc logged in successfully
**.**
You are telling it to reload the page for every it by using beforeEach:
beforeEach(function () {
browser.get('https://login/');
});
Use beforeAll instead:
beforeAll(function () {
browser.get('https://login/');
});

Shareds Behavior Jasmine + Protractor

I'm new with Protractor and jasmine framework to test an AngularJS Application.
I whould like to reuse some of my scenarios, like Login feature can call in all scenarios of my suite.
This is my login_test.js
module.exports = function(testName, testFn) {
const loginPage = pages.login;
const mainPage = pages.main;
var protractor;
describe('common Login suite', function() {
browser.ignoreSynchronization = true;
beforeEach(function() {
});
afterAll(function() {
browser.manage().deleteAllCookies();
});
it(testName, function() {
browser.get('http://localhost:9000/');
loginPage.typeUserName('bxxxxx');
loginPage.typePassword('xxxxxx');
loginPage.clickLogin();
});
});
}
And here I have the remote_terminal feature, here I need call Login feature to perfom login in my scenario.
var loginSuite = require('./login_test.js');
loginSuite('login Suite terminal feature', function(browser) {
describe('description', function() {
console.log('describe');
it('it', function() {
console.log('it');
});
});
});
But when this spec (remote_terminal) is called to run I got this message on my console
Started
Spec started
.
common Login suite
✓ login Suite terminal feature
As you can see the describe and IT in the remote_terminal spec aren't ran.
Demo:
http://pavelbogomolenko.github.io/dry-principles-with-protractor.html
You can use pageObjects to achieve reusable code accross your test,
Let us create a new js file for login page as login_page.js as below,
var login_page = function(){
this.performLogin = function(){
//add code for performing login operation.
}
}
module.exports = new login_page();
Now you can import the login_page.js in all 'specs' and can call the performLogin() method whenever required.
Look at the example spec.js below,
describe("Test pageobject code",function(){
var login_page = require("login_page.js");
beforeAll(function(){
login_page.performLogin();
})
it("simple test to perform after login action is performed",function()
//do whatever you want to test
})
})

Protractor: Async timing out, I think because it won't find an element

UPDATE #2: Traced back to the web app using $timeout instead of $interval. Explained here http://www.protractortest.org/#/timeouts under waiting for page synchronization
UPDATE: So I threw in browser.ignoreSynchronization=true; browser.sleep(5000);for the second test and it works. Not sure why.... The login page works perfectly without it. Best guess now is that it's a running script so it never finishes synchronizing???? Not really sure why it doesn't synchronize.
So more or less, how come I would need to ignore synchronization knowing that the site is angular???????
I'm using Protractor with the Jasmine framework.
Tests have been working up to this point.
I think Protractor cannot find my element and therefore times out. I can't figure out why it won't find my element as it does perfectly fine in earlier tests.
My conf.js
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js'],
allScriptsTimeout: 10000,
onPrepare: function() {
var SpecReporter = require('jasmine-spec-reporter');
jasmine.getEnv().addReporter(new SpecReporter({displayStacktrace: 'all'}));
},
jasmineNodeOpts: {
showColors: true,
isVerbose: true,
realtimeFailure: true,
includeStackTrace: true,
defaultTimeoutInterval: 10000,
print: function() {}
}
};
Current spec.js
describe('Authorizing newly created account', function() {
//This test works fine
it('should navigate back to login and login', function() {
browser.get('website');
element(by.model('$parent.username')).sendKeys('user');
element(by.model('$parent.password')).sendKeys('test');
element(by.buttonText('Login')).click();
});
//This one doesn't
it('should navigate to organizations', function() {
//DOESN'T WORK
var button = element(by.id('btn_organizations'));
button.click();
});
});
The snippet of HTML I'm trying to get ("Organization" link)
<li ng-if="user.administrator || user.organizationAdministrator">
<a ui-sref="organizations" ng-click="closeNav()" id="btn_organizations">
<span class="glyphicons glyphicons-tree-structure"></span>
<span class="hidden-sm"><g:message code="organizations" /></span>
</a>
</li>
I thought since the organizations had a ID I could use it to access it, but Protractor doesn't seem to like it.
I then get the error
-Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL
I really hope this isn't something dumb I'm missing.
Try all those options, it should work with the call back :
describe('Authorizing newly created account', function() {
beforeEach(function(done) {
done();
}, 10000);
//This test works fine
it('should navigate back to login and login', function() {
browser.get('website');
element(by.model('$parent.username')).sendKeys('user');
element(by.model('$parent.password')).sendKeys('test');
element(by.buttonText('Login')).click();
},10000);
//This one doesn't
it('should navigate to organizations', function() {
//DOESN'T WORK
var button = element(by.id('btn_organizations'));
button.click();
},10000);
},10000);
Take a look into this question and how i have resolved it : Time out problem

How to say protractor to wait till page loads?

My application taking some to page the login page.So protractor trying to enter the user name before page loads.So i need to say protractor to wait till the login page loads.
Could you please help me what command I need to use for this and where I need to use?(Please modify my code to add the wait command)
PFB for my onPrepare and beforeeach function
onPrepare: function() {
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
})
}
beforeEach(function() {
browser.get('https://accounts.google.com/');
//browser.manage().timeouts().pageLoadTimeout(30000);
//browser.manage().timeouts().implicitlyWait(5000);
//browser.sleep( 10000 );
//browser.waitForAngular();
});
I used those commented functions,but it didn't work for me.
Please guide me.thanks in advance.
Assuming you want to click the Get Started button, wait for the button to become clickable:
var EC = protractor.ExpectedConditions;
var getStarted = element(by.css('button[title="Get started"]'));
browser.wait(EC.elementToBeClickable(getStarted), 5000);
getStarted.click();
Use the wait command: browser.driver.wait(condition, timeout);
onPrepare: function() {
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
});
}
beforeEach(function() {
browser.driver.get('https://accounts.google.com/');
return browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function (url) {
return url.indexOf('https://accounts.google.com/') > -1;
});
}, 5000);
//whatever you want after
});
you can wait for any condition like that.
Also, google f.e is not an angular page, so you should use:
browser.driver.get instead of protractors browser.get,
or it will wait for angular on the page.

protractor expect currenturl fails

I'm trying to get an e2e test running against my local server and test that the resulting url (after a navigational button has been clicked) is the correct result. However the resulting url is always false.
My code is shown below:
HTML:
//http://localhost/#/current_Page
<html>
<head><title></title></head>
<body>
//should change the current url to
//http://localhost/#/new_page
<button class="button" ng-click="change_page()">Change Page</button>
</html>
TEST CODE:
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
var ptor;
describe('Test 1', function() {
var ptor = protractor.getInstance();
ptor.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
expect(ptor.currentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
The issue is the current url after clicking the button remains #/current_url and does not change to the expected result #/new_page.
Does anyone know where I have gone wrong?
After search for the answer to this question I figured it out myself
The current url does not fail, I was not waiting for the promise to return to angular. The ammended code below shows where I had gone wrong
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
var ptor;
describe('Test 1', function() {
var ptor = protractor.getInstance();
ptor.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
ptor.waitForAngular();
expect(ptor.currentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
This then waits for angular to route to the new page and update any bindings and then proceeds to check the expected result which is now what I would expect it to be.
Please be advised that this does not solve all issues relating to unexpected getCurrentUrl() results. if using driver.findElement() you may need to refer to JulieMR's answer to this question
I hope this helps someone stuck on this issue.
In Protractor 1.5.0 protractor.getInstance(); isn't working anymore, so you have to use browser instead.
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
describe('Test 1', function() {
browser.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
browser.waitForAngular();
expect(browser.getCurrentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
You can also write a custom expected condition to wait for current url to being equal a desired one. Besides, use browser and element notations:
browser.get("#/current_page");
it("change page and current url", function() {
element(by.css(".button")).click();
browser.wait(urlChanged("#/new_page")), 5000);
});
where urlChanged is:
var urlChanged = function(url) {
return function () {
return browser.getCurrentUrl().then(function(actualUrl) {
return actualUrl.indexOf(url) >= 0;
});
};
};
Or, a Protractor>=4.0.0 solution and the urlContains expected condition:
element(by.css(".button")).click();
var EC = protractor.ExpectedConditions;
browser.wait(EC.urlContains("#/new_page"), 5000);

Resources