I'm using protractor for e2e testing, but I have strange problem. My tests worked fine on 'Chrome', but when I choose 'Internet Explorer' some objects not found and my tests fails. Why? And what I may do with that?
Examples of failing specs:
describe('ps-grid-column-filter-range_spec_1.1.a', function() {
var config = browser.params;
var req = config.req_lib_filter;
require(req);
var tester_column_number = config.column_number_filter;
var tester_url = config.url_filter;
var filter_field = element(by.xpath("//td[#class='ng-scope n-grid__filter']["+ tester_column_number +"]"));
var balloon_info = $('div[class="n-balloon n-balloon_bottom_left n-balloon_can_close n-balloon_info"]');
beforeEach(function() {
browser.get(tester_url);
});
it('balloon should contain text',function(){
filter_field.click();
browser.sleep(3000);
var balloon_text = (balloon_info.element(by.css('div'))).element(by.css('span'));
var height = balloon_info.getAttribute("style");
expect(height).toContain("height: 50px;");
expect(balloon_text.getText()).toContain('Допустимо вводить диапазон от');
expect(balloon_text.getText()).toContain('Например:');
if (true) console.log("ps-grid-column-filter-range_spec_1.1.a : text1");
});
it('should show balloon',function(){
filter_field.click();
browser.sleep(3000);
if (balloon_info.isPresent()) expect(balloon_info.isDisplayed()).toBe(true);
else expect(true).toBe(false);
if (true) console.log("ps-grid-column-filter-range_spec_1.1.a : text2");
});
});
In 'Chrome' it okey, but in the 'Internet Explorer' I get an error:
NoSuchElementError: No element found using locator BycssSelector("div[class="n-balloon n-balloon_bottom_left n-balloon_can_close n-balloon_info"]")
With IE it's always something extra you should do to make things work.
In your case, I would try the following:
add an Explicit Wait instead of the browser.sleep():
filter_field.click();
var EC = protractor.ExpectedConditions;
browser.wait(balloon_info, 5000);
click the filter through javascript:
browser.executeScript("arguments[0].click();", filter_field);
Related
I have a login function that I'm using for a Protractor test, it looks like this:
var config = require("../helpers/config.js");
var login = function() {
browser.driver.get(config.dsp.url);
browser.driver.findElement(by.name("userName")).sendKeys(config.dsp.user);
browser.driver.findElement(by.name("password")).sendKeys(config.dsp.password);
return browser.driver.findElement(by.name("submit")).click().then(function() {
return browser.driver.wait(function() {
return browser.driver.isElementPresent(browser.driver.findElement(by.className("sample-class-name")));
}, 360000);
});
}
module.exports = login;
I can't use any of the protractor specific hooks because Angular is not used on this page, so I have to use the underlying webdriver API. The problem is, I can't seem to figure out how to wait until an element is visible using this wrapped webdriver object. Any help would be appreciated.
Try with the expected conditions from the underlying driver:
var config = require("../helpers/config.js");
var until = require('selenium-webdriver').until;
var login = function() {
var driver = browser.driver;
driver.get(config.dsp.url);
driver.findElement(by.name("userName")).sendKeys(config.dsp.user);
driver.findElement(by.name("password")).sendKeys(config.dsp.password);
driver.findElement(by.name("submit")).click();
return driver.wait(until.elementLocated(by.css(".sample-class-name")), 10000)
.then(e => driver.wait(until.elementIsVisible(e)), 10000);
}
module.exports = login;
I tried all variations mentioned in this Q&A:
first one
element(by.css('[ng-click="vm.openNewPage()"]')).click().then(function () {
expect(element(by.css('[ng-click="vm.submitButtonOfThatPage()"]')).isPresent()).toBe(true);
});
second one
element(by.css('[ng-click="vm.openNewPage()"]'));
browser.waitForAngular();
expect(element(by.css('[ng-click="vm.submitButtonOfThatPage()"]')).isPresent()).toBe(true);
third one:
element(by.css('[ng-click="vm.openNewPage()"]'));
browser.sleep(1)
browser.waitForAngular();
expect(element(by.css('[ng-click="vm.submitButtonOfThatPage()"]')).isPresent()).toBe(true);
none of them passes test: Expected false to be true.
except this one with browser.sleep(1000)
element(by.css('[ng-click="vm.openNewPage()"]'));
browser.sleep(1000)
expect(element(by.css('[ng-click="vm.submitButtonOfThatPage()"]')).isPresent()).toBe(true);
Putting some seconds for sleep time is obviously not a solution.
What am I missing or what should I do to evaluate test successfully
Protractor version is: Version 2.1.0 with Jasmine2 framework
This is my command to start test:
C:\projects\eucngts\e2e\app>protractor conf.js --baseUrl=http://localhost:56225/euc/
And these are my relevant codes:
// conf.js
exports.config = {
directConnect: true,
seleniumAddress: 'http://localhost:4444/wd/hub',
framework: 'jasmine2',
specs: [
'./views/account/loginSpec.js'
,'./views/inStudents/inStudentsSpec.js'
]
}
//Spec File
describe('Testing Students Page', function () {
var inStudents: InStudents = require('./inStudents.js');
var defs: Defs = require('../defs.js');
it('should check cell 2 2 ', function () {
inStudents.createNewInStudent()
});
});
//Testing file
class InStudents {
createNewInStudent() {
element(by.css('[ng-click="vm.openNewPage()"]'));
browser.sleep(1000)
expect(element(by.css('[ng-click="vm.submitButtonOfThatPage()"]')).isPresent()).toBe(true);
}
}
module.exports = new InStudents();
Instead of a browser.sleep() delay, make it explicit with browser.wait() and wait for the element to become present:
var submitButton = element(by.css('[ng-click="vm.submitButtonOfThatPage()"]'));
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(submitButton), 5000);
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
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);
I am trying to write unit tests for my Angular.js application but I cannot manage to inject what I need (it is not able to find a suitable provider).
Does anyone see what I missed?
Firefox 21.0 (Linux) filter staticList should convert static list object into its display value FAILED
Error: Unknown provider: staticListProvider <- staticList in /path/to/my-app/public/third-party/angular/angular.js (line 2734)
createInjector/providerInjector<#/path/to/my-app/public/third-party/angular/angular.js:2734
getService#/path/to/my-app/public/third-party/angular/angular.js:2862
createInjector/instanceCache.$injector<#/path/to/my-app/public/third-party/angular/angular.js:2739
getService#/path/to/my-app/public/third-party/angular/angular.js:2862
invoke#/path/to/my-app/public/third-party/angular/angular.js:2880
workFn#/path/to/my-app/test/lib/angular/angular-mocks.js:1778
angular.mock.inject#/path/to/my-app/test/lib/angular/angular-mocks.js:1764
#/path/to/my-app/test/unit/filtersSpec.js:19
#/path/to/my-app/test/unit/filtersSpec.js:16
#/path/to/my-app/test/unit/filtersSpec.js:3
The application:
angular.module('myApp', ['myAppFilters', 'ui.bootstrap', '$strap.directives']).
// Some other stuff
The filters:
"use strict";
angular.module('myAppFilters', []).
filter('staticList', function () {
return function (listItem) {
if (!listItem) {
return '';
}
return listItem.value;
};
});
The test:
'use strict';
describe('filter', function () {
beforeEach(angular.module('myAppFilters'));
describe('staticList', function () {
it('should convert static list object into its display value',
inject(function (staticList) {
expect(undefined).toBe('');
expect({key: 'A', value: 'B'}).toBe('B');
}));
});
});
The Karma configuration:
basePath = '../';
files = [
JASMINE,
JASMINE_ADAPTER,
'public/third-party/jquery/*.js',
'public/third-party/angular/angular.js',
'public/third-party/angular/i18n/angular-*.js',
'public/third-party/moment/moment.min.js',
'public/third-party/moment/moment-*.js',
'public/js/**/*.js',
'test/lib/**/*.js',
'test/unit/**/*.js'
];
colors = true;
autoWatch = true;
browsers = ['Firefox'];
junitReporter = {
outputFile: 'test_out/unit.xml',
suite: 'unit'
};
If anybody wants to see the full code, the application repository is here: https://github.com/adericbourg/GestionCourrier
Thanks a lot,
Alban
In your inject code
it('should convert static list object into its display value',
inject(function (staticList) {
expect(undefined).toBe('');
expect({key: 'A', value: 'B'}).toBe('B');
}));
replace "inject(function (staticList)" with "inject(function (staticListFilter)". This is some random convention angular is following. You can check comments on this page for more info http://docs.angularjs.org/tutorial/step_09
I faced similar problem, but in my case my filter name contained suffix 'Filter' which caused the same injection problem.
.filter('assetLabelFilter', function(){
return function(assets, selectedLabels){
// Implementation here
};
});
I was finally able to solve the problem by manually injecting the filter to my test
'use strict';
describe('assetLabelFilter', function() {
beforeEach(module('filters.labels'));
var asset1 = {labels: ['A']};
var asset2 = {labels: ['B']};
var asset3 = {labels: []};
var asset4 = {labels: ['A', 'B']};
var assets = [asset1, asset2, asset3, asset4];
var assetLabelFilter;
beforeEach(inject(function($filter) {
assetLabelFilter = $filter('assetLabelFilter');
}));
it('should return only assets with selected label', function() {
var selectedLabels = ['B'];
expect(assetLabelFilter(assets, selectedLabels)).toEqual([asset2, asset4]);
});
});
The nice answer above made me realize that in order to use the angular tutorial way:
it('should ', inject(function(assetLabelFilter) {
var selectedLabels = ['B'];
expect(assetLabelFilter(assets, selectedLabels)).toEqual([asset2, asset4]);
}));
The filter name can't have the suffix 'Filter' because it is magic word as mentioned in the answer above.
To demonstrate the scenario I also created a Plunker