I am experiencing problems when running the following script on a specific site. The script works on firefox but on chrome it crashes with the following stacktrace:
Protractor.waitForAngular() - Locator: By(css selector, *[id="loading-app-content"])
at WebDriver.schedule (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:377:17)
at ProtractorBrowser.executeAsyncScript_ (/usr/local/lib/node_modules/protractor/built/browser.js:232:28)
at runWaitForAngularScript (/usr/local/lib/node_modules/protractor/built/browser.js:263:30)
at ProtractorBrowser.waitForAngular (/usr/local/lib/node_modules/protractor/built/browser.js:266:16)
at ElementArrayFinder.getWebElements (/usr/local/lib/node_modules/protractor/built/element.js:154:29)
at ElementFinder.isPresent (/usr/local/lib/node_modules/protractor/built/element.js:904:46)
at /usr/local/lib/node_modules/protractor/built/expectedConditions.js:86:20
at /usr/local/lib/node_modules/protractor/built/expectedConditions.js:63:20
at /usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:716:14
at TaskQueue.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2913:14)
My protractor-conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub', // This is targetting your local running instance of the selenium webdriver
specs: [
'./features/**/*.feature'
],
capabilities: {
browserName: 'chrome',
},
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'), // Here it is
cucumberOpts: {
format: 'pretty',
require: './features/step_definitions/**/*.js' // This is where we'll be writing our actual tests
},
allScriptsTimeout: 11000,
onPrepare: function() {
browser.driver.manage().window().setSize(1400, 900);
browser.driver.manage().window().maximize();
},
useAllAngular2AppRoots: true
};
The test:
test = function() {
var EC = protractor.ExpectedConditions;
var el= element(by.className("preview-toggle"));
this.Given(/^I open up the application$/, function (callback) {
browser.get('foo.com').then(callback);
});
this.When(/^I click on add$/, function (callback) {
// Write code here that turns the phrase above into concrete actions
browser.wait(EC.invisibilityOf(element(by.id("loading-app-content"))), 30000).then(function () {
browser.wait(EC.presenceOf(element(by.css(".preview-toggle"))), 30000).then(function () {
browser.wait(EC.visibilityOf(element(by.css(".preview-toggle"))), 30000).then(function () {
browser.wait(EC.elementToBeClickable(element(by.css(".preview-toggle"))), 30000).then(function () {
el.click().then(callback);
});
});
});
});
});
this.Then(/^I should be the best$/, function (callback) {
callback();
});
};
module.exports=test;
Thing is every actions I do (even clicking on body) gives this error. Any other angular page works in chrome.
My specfic question is: what is causing chrome to crash?
Related
I am trying to update protractor config on the run time, because spec file are being read from external excel file.
Below is my config:
export let config = {
allScriptsTimeout: RunConfig.allScriptsTimeout,
capabilities: {
browserName: RunConfig.browser
},
directConnect: true,
baseUrl: RunConfig.baseUrl,
framework: RunConfig.framework,
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: RunConfig.defaultTimeoutInterval,
print: function () {
}
},
onPrepare() {
bot.fullScreen();
Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
beforeLaunch() {
let spec = new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
},
resultJsonOutputFile: RunConfig.resultFile
}
According to this it should update config in beforeLaunch
==========================
ReadSpec Function
readSpecs() {
fs.readFile(RunConfig.runManager, (err, buf) => {
if(!err && buf) {
let wb = XLSX.read(buf, { type: 'buffer' });
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
} else {
return [];
}
});
}
I add explanation inline:
XLSX = require('xlsx');
// change readSpecs() to sync style
readSpecs() {
let wb = XLSX.readFile(RunConfig.runManager);
let sheet = wb.Sheets[sheetNames.specs]; //reading specs
let specArr = XLSX.utils.sheet_to_json(sheet);
let spec;
specArr.forEach(element => {
spec.push(element.spec);
});
return spec;
}
export let config = {
// specify value for `specs`, and it require `Xlsx.readSpecs()`
// does not return promise-like object.
specs: Xlsx.readSpecs(),
onPrepare() {
bot.fullScreen();
// you need to move Xlsx.readExcel(); to the top
// when protractor run into onPrepare() function,
// it means protractor runner had accepted your passed-in config
// the runner won't accept any changes to the config once it accepted.
// Xlsx.readExcel();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: true
}
}));
},
// beforeLaunch() is unnecessary
// beforeLaunch() {
// let spec = new Promise((resolve) => {
// resolve({
// specs: Xlsx.readSpecs()
// });
// });
// },
};
beforeLaunch() can't change the config yet. There is no hooks can change the config before protractor read it. The only way is to give a pre-know value to specs and not allow promise-like value.
If your Xlsx.readExcel() or Xlsx.readSpecs() return promise, you have to use another way to implement it.
You aren't using the local variable spec for anything in the beforeLaunch function. The example in the link you posted is returning the resolved promise. You need to get rid of the local variable and return the promise like this:
beforeLaunch() {
return new Promise((resolve) => {
resolve({
specs: Xlsx.readSpecs()
});
});
}
I do end to end test using protractor.When I start up the test this message appears to me
conFusion App E2E Testing menu 0 item should show the first comment author as
Message:
Failed: No element found using locator: by.model("FiltText")
How can I make the protractor wait until element appears in the DOM?
the corresponding protractor configuration code is :
exports.config = {
allScriptsTimeout:11000,
specs: [
'e2e/*.js'
],
capabilities: {
'browserName': 'chrome'
},
baseUrl: 'http://localhost:3001/',
framework: 'jasmine',
directConnect: true,
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
}
};
scenarios.js code that contain e2e test
describe('menu 0 item', function() {
beforeEach(function() {
browser.get('index.html#/menu/0');
});
it('should have a name', function() {
var name = element(by.binding('dish.name'));
expect(name.getText()).
toEqual('Uthapizza Hot $4.99');
});
it('should show the number of comments as', function() {
expect(element.all(by.repeater('comment in dish.comments'))
.count()).toEqual(5);
});
it('should show the first comment author as', function() {
element(by.model('FiltText')).sendKeys('author');
expect(element.all(by.repeater('comment in dish.comments'))
.count()).toEqual(5);
var author = element.all(by.repeater('comment in dish.comments'))
.first().element(by.binding('comment.author'));
expect(author.getText()).toContain('25 Cent');
});
});
You can use ExpectedConditions:
var EC = protractor.ExpectedConditions;
var timeout = 5000; // in miliseconds
// Waits for the element to be present on the dom.
browser.wait(EC.presenceOf(element(by.model("FiltText"))), timeout);
// Here you can safely use your element, because here it is guaranted to be present.
Because protractor uses control flow, this command will not finish until the FiltText is visible or the time is greater than timeout.
More information here:
http://www.protractortest.org/#/api?view=ProtractorExpectedConditions
there are many ways to achieve this, for example :
Use protractor.ExpectedConditions API
Wait for some seconds to ensure everything is loaded, here is a sample code :
utils.js
'use strict';
/**
* Navigate to an url and wait some seconds
* #param {string} path The path
* #param {seconds} [seconds] The number of seconds to wait for
* #returns {Promise}
* #see waitSomeSeconds
*/
function navigateAndWait(path, seconds) {
return browser.get(path)
.then(function () {
// Wait some seconds until page is fully loaded
return waitSomeSeconds(seconds);
});
}
/**
* Wait some seconds (default is 3)
* #param {int} [seconds]
* #returns {Promise}
*/
function waitSomeSeconds(seconds) {
return browser.sleep((seconds || 3) * 1000);
}
module.exports = {
navigateAndWait: navigateAndWait,
waitSomeSeconds: waitSomeSeconds
}
Then you can use it in your tests :
**sampleSpec.js**
'use strict';
var util = require('./utils');
describe('Products', function () {
it('should be redirected to products page after login', function (done) {
util.waitSomeSeconds().then(function() {
browser.getCurrentUrl().then(function (value) {
var relativePath = value.substring(value.lastIndexOf('/'));
expect(relativePath).toEqual('/products');
done();
});
});
it('should navigate to products list', function() {
return util.navigateAndWait('/products');
});
it('should display title with correct data', function() {
expect(element(by.css('h1')).getText()).toBe('Newest products');
});
});
I have simple test doing login and trying to check if it's success:
describe('My Angular App', function () {
describe('visiting the main homepage', function () {
beforeEach(function () {
browser.get('/');
element(By.id("siteLogin")).click();
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
element(By.id("formLoginButton")).click().then(function() {
browser.getCurrentUrl().then(function(url){
expect(url).toContain("profile");
});
});
});
});
});
It goes well until that last part where I'm checking URL, and in Selenium Server I get:
INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
and also I get:
Failures:
1) My Angular App visiting the main homepage should login successfully
Message:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My protractor-conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:8080/Mysite',
capabilities: {
'browserName': 'firefox' // muste use firefox because I can't get .click() to work in Chrome
},
specs: [
'spec-e2e/*.js'
],
framework: 'jasmine2',
jasmineNodeOpts: {
isVerbose: true,
showColors: true,
defaultTimeoutInterval: 30000
}
};
I appreciate any help on this one.
Thanks
Looks like there is a non-Angular page opened after a click. If this is the case, you need to turn the synchronization between Protractor and Angular off:
afterEach(function () {
browser.ignoreSynchronization = false;
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
browser.ignoreSynchronization = true;
element(By.id("formLoginButton")).click().then(function() {
expect(browser.getCurrentUrl()).toContain("profile");
});
});
Note that you don't need to explicitly resolve the promise returned by getCurrentUrl and can let the expect() do that for you implicitly.
You may also need to wait for the URL to change:
var urlChanged = function(desiredUrl) {
return browser.getCurrentUrl().then(function(url) {
return url == desiredUrl;
});
};
browser.wait(urlChanged("my desired url"), 5000);
I have been trying to connect to MSSQL database using node module in my protractor tests. I tried both the methods below but each time I am either getting undefined is not a function or getting cannot read property of "query/execute".
Error: [launcher] Running 1 instances of WebDriver
[launcher] Error: TypeError: undefined is not a function
at exports.config.onPrepare (....\conf\Conf.js:39:28)
I have my connection defined in conf.js
var HtmlReporter = require('protractor-html-screenshot-reporter');
var mysql = require('../node_modules/mssql');
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub', //desktop
allScriptsTimeout: 40000,
baseUrl: 'https://myurl.com/#/',
// frameworks to use
frameworks: 'jasmine',
//Capabilities to be passed to the webdriver instance.
multiCapabilities: [{
'browserName': 'chrome'
// }, {
// 'browserName': 'firefox'
//},
// {
// 'browserName': 'internet explorer'
}],
// Spec patterns are relative to the current working directory.
specs: [
'../tests/HomePage.js'
],
onPrepare: function() {
var sql = require('mssql/');
var config = {
server : '*****',
user : 'myusername',
password : 'pass',
database: 'mydb'
};
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: '/MyDirectory/screenshots'
}));
},
jasmineNodeOpts: {
showColors: true
}
};
In my Test, I did the following: test.js
describe ( " page test , function() {
it('Should add customer', function() {
blah blah....
});//This click will create a record in the backend
// I am attempting to get the record:
function runQuery() {
var connection = new sql.Connection(config, function(err) {
var request = new sql.Request(connection); // or: var request = connection.request();
request.query('select top 1 as result from customers', function(err, recordset) {
// ... error checks
console.log("this is the request: " + request);
console.dir(recordset);
});
});
};
I used dqlserver unofficial and it worked pretty well. We use Windows authentication to login to MSSQL studio so use the below.
var sql = require('node-sqlserver-unofficial');
var conn_str = "Driver={SQL Server Native Client 11.0};Server={your server};Database={your database};Trusted_Connection={Yes}";
sql.open(conn_str, function (err, conn) {
if (err) {
console.log("Error opening the connection!");
return;
}
conn.queryRaw("SELECT TOP 10 * FROM Employee", function (err, results) {
if (err) {
console.log("Error running query!");
return;
}
for (var i = 0; i < results.rows.length; i++) {
console.log("\n")
console.log("Record Info: ");
for (var j = 0; j < results.rows.length; j++) {
console.log(results.rows[i][j]);
}
}
});
});
Download MSSQL Unofficial package from here:
https://www.npmjs.com/package/node-sqlserver-unofficial
Hi I have created a custom component that uses an external template and requires a service, when the template is defined as external, the unit tests break.
template reference in main.html <cc-accordion items="genres"></cc-accordion>
This is the component js
angular.module("ccAccordion", [])
.directive("ccAccordion", function () {
return {
restrict: "AE",
templateUrl: "components/accordion/accordion.html",
scope: {
items: "="
},
link: function (scope) {
scope.$watch("items", function (items) {
angular.forEach(items, function (item) {
item.selected = false;
});
scope.select = function (index) {
(scope.items[index].selected === true ) ? scope.items[index].selected = false : scope.items[index].selected = true;
angular.forEach(scope.items, function (item, key) {
if(key !== index) {
item.selected = false;
}
});
};
});
}
};
});
here is the unit test
describe('ccAccordion', function () {
var elm, scope;
beforeEach(module('ccAccordion'));
beforeEach(inject(function ($rootScope, $compile) {
elm = angular.element(
'<cc-accordion items="genres"></cc-accordion>'
);
scope = $rootScope;
scope.genres = [{
title: 'Scifi',
description: 'Scifi description'
}, {
title: 'Comedy',
description: 'Comedy description'
}];
$compile(elm)(scope);
scope.$digest();
}));
it('should create clickable titles', function () {
var titles = elm.find('.cc-accord h2');
expect(titles.length).toBe(2);
expect(titles.eq(0).text().trim()).toBe('Scifi');
expect(titles.eq(1).text().trim()).toBe('Comedy');
});
it('should bind the content', function () {
var contents = elm.find('.cc-accord-content p');
expect(contents.length).toBe(2);
expect(contents.eq(0).text().trim()).toBe('Scifi description');
expect(contents.eq(1).text().trim()).toBe('Comedy description');
});
it('should change active content when header clicked', function () {
var titles = elm.find('.cc-accord h2'),
divs = elm.find('.cc-accord');
// click the second header
titles.eq(1).find('a').click();
// second div should be active
expect(divs.eq(0)).not.toHaveClass('active');
expect(divs.eq(1)).toHaveClass('active');
});
});
here is the template
<div class="cc-accord" ng-repeat="item in items" ng-class="{active:item.selected}" ng-click="select($index)">
<h2><a>
{{item.title}} <cc-up-down-arrow></cc-up-down-arrow>
</a></h2>
<div class="cc-accord-content"><p>{{item.description}}</p></div>
</div>
if I put the template in the directive the tests pass. I've tried editing the karma.conf to use a preprocessor and 'ng-html2js' but can't get it to work. Any help would be much appreciated. Thanks in advance
here is my karma.conf, I'm using mean stack to scaffold the app
// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html
module.exports = function (config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'client/bower_components/jquery/dist/jquery.js',
'client/bower_components/angular/angular.js',
'client/bower_components/angular-mocks/angular-mocks.js',
'client/bower_components/angular-resource/angular-resource.js',
'client/bower_components/angular-animate/angular-animate.js',
'client/bower_components/angular-cookies/angular-cookies.js',
'client/bower_components/angular-sanitize/angular-sanitize.js',
'client/bower_components/angular-route/angular-route.js',
'client/bower_components/lodash/dist/lodash.compat.js',
'client/bower_components/angular-socket-io/socket.js',
'client/bower_components/angular-ui-router/release/angular-ui- router.js',
'client/app/app.js',
'client/app/**/*.js',
'client/components/**/*.js',
'client/app/**/*.html',
'client/components/**/*.html'
],
preprocessors: {
'client/components/accordion/accordion.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
/*stripPrefix: 'client/',
stripSufix: '.ext',
// prepend this to the
prependPrefix: 'served/'*/
},
ngJade2JsPreprocessor: {
stripPrefix: 'client/'
},
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
New matcher function for jasmine 2.0
beforeEach(function () {
jasmine.addMatchers({
toHaveClass: function () {
return {
compare: function (actual, expected) {
var classTest = actual.hasClass(expected);
classTest ? classTest = true : classTest = false;
return {
pass: classTest,
message: 'Expected ' + angular.mock.dump(actual) + ' to have class ' + expected
};
}
};
}
});
});
Usage
expect(divs.eq(0)).not.toHaveClass('active');
expect(divs.eq(1)).toHaveClass('active');
I just compared you karma config file with mine, seeing following differences:
In field preprocessors, try providing an array instead of a single processor
Use ngHtml2JsPreprocessor field
Your karma conf file should contain following:
preprocessors: {
'client/components/accordion/accordion.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
stripPrefix: 'client/'
}
As Himmet said the karma.conf file needs to be edited and you need to put the location of the template into the preprocessors section
preprocessors: {
'client/components/accordion/accordion.html': ['ng-html2js'],
'another-template-path/template.html': ['ng-html2js']
},
ngHtml2JsPreprocessor: {
stripPrefix: 'client/'
}