How to read locators from a json file in protractor? - protractor

I want to develop a framework where i keep all the locators at one place, in a json file say test.json. like this.
{
"yourName": "by.model('yourName')"
}
And I want to read this in specs as below.
var test = require('./test.json');
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get('https://angularjs.org');
var webElement = element(testtest.yourName);
webElement.sendKeys('write first protractor test');
});
});
but when i do this getting error as Failed: Invalid locator with following error trace.
Failures:
1) angularjs homepage todo list should add a todo
Message:
Failed: Invalid locator
Stack:
TypeError: Invalid locator
at Object.check [as checkedLocator] (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\by.js:267:9)
at WebDriver.findElements (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\webdriver.js:919:18)
at C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\built\element.js:159:44
at ManagedPromise.invokeCallback_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:1379:14)
at TaskQueue.execute_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2913:14)
at TaskQueue.executeNext_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2896:21)
at asyncRun (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2775:27)
at C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:639:7
at process._tickCallback (internal/process/next_tick.js:103:7)Error
at ElementArrayFinder.applyAction_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\built\element.js:396:27)
at ElementArrayFinder._this.(anonymous function) [as sendKeys] (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\built\element.js:99:30)
at ElementFinder.(anonymous function) [as sendKeys] (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\built\element.js:730:22)
at Object.<anonymous> (E:\ui\TestTest\todo-spec.js:9:20)
at C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:94:23
at new ManagedPromise (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:1082:7)
at controlFlowExecute (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:80:18)
at TaskQueue.execute_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2913:14)
at TaskQueue.executeNext_ (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2896:21)
at asyncRun (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2820:25)
From: Task: Run it("should add a todo") in control flow
at Object.<anonymous> (C:\Users\karunakaralchala\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:79:14)
From asynchronous test:
Error
at Suite.<anonymous> (E:\ui\TestTest\todo-spec.js:4:7)
at Object.<anonymous> (E:\ui\TestTest\todo-spec.js:3:5)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
Is there any better way to do this? or what should i need to make it work?

Probably not the direct answer to the question, but I think you are not attempting the problem in a traditional way and sort of partially reinventing the wheel.
Instead of keeping locators in a separate JSON structure, organize them into Page Objects - separate page objects (including element locators and methods to interact with a page) for separate pages or parts of pages.

This should work.
test.json
{
"siteURL": "https://angularjs.org",
"locators": {
"todoText": {
"model": "todoList.todoText"
}
}
}
spec.js
var test = require('./test.json');
describe('angularjs homepage todo list', function() {
it('should add a todo', function() {
browser.get(test.siteURL);
var webElement = element(by.model(test.locators.todoText.model));
webElement.sendKeys('write first protractor test');
});
});
One complete example using BDD Cucumber, json and pageobject model here. https://github.com/aluzardo/protractor-cucumber-tests/

One simple mistake in your approach.
The values from JSON are read as string and you are passing a string to element() and not a locator(not a by object)
var webElement = element(test.yourName); // Incorrect. test.yourName returns string
Change it way and voila ! You should be good. Use eval(). Refer here
var webElement = element(eval(test.yourName));

Related

allure.createAttachment exception error - Cannot read property 'currentStep' of undefined

I can successfully add screenshots to allure reports, but i get the following exception error:
error:
TypeError: Cannot read property 'currentStep' of undefined
at Allure.addAttachment (/Users//xxx/xxx/xxx/node_modules/allure-js-commons/index.js:86:45)
at Allure.createAttachment (/Users/xxx/xxx/xxx/node_modules/allure-js-commons/runtime.js:48:29)
at /Users/xxx/xxx/xxx/lib/class/class-name.js:30:20
at process._tickCallback (internal/process/next_tick.js:68:7)
class:
browser.takeScreenshot().then(function (png) {
allure.createAttachment(title, new Buffer(png, 'base64'));
}).catch((error: any) => console.log(error));
const allure = require('mocha-allure-reporter');
allure is a global identifier, injected by reporter to your code.
Add the following line to the top of your file to tell Typescript about it
declare const allure: any;
I think createAttachment requires a callback function and not a buffer being passed directly.
Can you try changing your code to reflect the following
browser.takeScreenshot().then(function (png) {
allure.createAttachment('Screenshot', function () {
return new Buffer(png, 'base64')
}, 'image/png')()
}).catch((error: any) => console.log(error));

Focusing on angular4 popup window with Protractor

I'm unable to get my UI test to focus on a popup window. At this stage, I'd be happy to simply click PayBill, wait for the popup window (which loads instantly), then click Cancel.
The latest version of my code reads:
paybillButton.click();
browser.sleep(500);
browser.getAllWindowHandles().then(function (handles) {
newWindowHandle = handles[1];
browser.switchTo().window(newWindowHandle).then(function () {
cancelButton.click();
});
});
But it keeps failing between browser.switchTo() and .window(newWindowHandle).then ...
Error:
Failed: null value in entry: handle=null
WebDriverError: null value in entry: handle=null
at Object.checkLegacyResponse (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/error.js:505:15)
at parseHttpResponse (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/http.js:509:13)
at doSend.then.response (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/http.js:440:13)
at process._tickCallback (internal/process/next_tick.js:103:7)
From: Task: WebDriver.switchTo().window(undefined)
at thenableWebDriverProxy.schedule (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:816:17)
at TargetLocator.window (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/webdriver.js:1755:25)
I've also tried the code below from Failed: null value in entry: name=null error while switching Popup window ...
function windowCount(count) {
return function () {
return browser.getAllWindowHandles().then(function (handles) {
return handles.length >= count;
});
};
};
browser.wait(windowCount(2), 10000);
browser.getAllWindowHandles().then(function (handles) {
browser.switchTo().window(handles[1]);
cancelButton.click();
});
But that's returning this error:
Failed: Wait timed out after 10002ms
TimeoutError: Wait timed out after 10002ms
at /usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2107:17
at ManagedPromise.invokeCallback_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:1366:14)
at TaskQueue.execute_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2970:14)
at TaskQueue.executeNext_ (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2953:27)
at asyncRun (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2813:27)
at /usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:676:7
at process._tickCallback (internal/process/next_tick.js:103:7)
From: Task: <anonymous wait>
at scheduleWait (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2094:20)
at ControlFlow.wait (/usr/local/lib/node_modules/protractor/node_modules/selenium-webdriver/lib/promise.js:2408:12)
The switchTo method is a wrapper to the selenium-webdriver switchTo method. The switchTo method returns a TargetLocator object and the TargetLocator object does not have a window method. The correct way to do this is to use the frame method.
browser.getAllWindowHandles().then((handles) => {
let newWindowHandle = handles[1];
browser.switchTo().frame(newWindowHandle).then(() => {
cancelButton.click();
});
});

Protractor stacktrace does not mention the line number on the .js file where the syntax issue or error occurs

This is my conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['C:\\Users\\meiyer\\Desktop\\Protractor_Tests\\specs\\specs.js'],
baseUrl: 'https://devcp.us.sunpowermonitor.com/#/dashboard',
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
//Options to be passed to Jasmine-node.
jasmineNodeOpts: {
onComplete: null,
isVerbose: true,
showColors: true,
includeStackTrace: true
}
};
This is my specs.js
var elhLoginpage = {
nameInput : element(by.model('user.UserName')),
passInput : element(by.model('model')),
submitButton :element(by.buttonText('sign in')),
setEmail: function(email) {
this.nameInput.sendKeys(email);
},
setPass: function(password) {
this.passInput.sendKeys(password);
},
clickSubmit:function(){
this.submitButton.click();
}
};
var elhHomepage = {
greetingText : element(by.css('.greeting-des')),
getgreetingText: function() {
this.greetingText.text();
}
};
describe('elhLoginpage login test', function() {
it('should land on homepage when valid username and password is entered',
function(){
elhLoginpage.setEmail('lease_id#test.com');
elhLoginpage.setPass('sun');
elhLoginpage.clickSubmit();
expect(elhHomepage.getgreetingText().toEqual('Hello lease');
});
});
I am executing the test on node.js command prompt as -> protractor conf.js. I am getting below stack trace. From the information below -I am not able to debug on which line number on either of the .js files the issue has occurred. Is there a way to activate this information on stacktrace?
Stacktrace -
C:\Users\meiyer\Desktop\Protractor_Tests>protractor conf.js
[15:40:56] I/hosted - Using the selenium server at
http://localhost:4444/wd/hub
[15:40:56] I/launcher - Running 1 instances of WebDriver
[15:40:58] E/launcher - Error: SyntaxError: missing ) after argument list
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Module.require (module.js:353:17)
at require (internal/module.js:12:17)
at
C:\Users\meiyer\AppData\Roaming\npm\node_modules\protractor\node_modules\
jasmine\lib\jasmine.js:71:5
at Array.forEach (native)
at Jasmine.loadSpecs
C:\Users\meiyer\AppData\Roaming\npm\node_modules\protr
actor\node_modules\jasmine\lib\jasmine.js:70:18)
[15:40:58] E/launcher - Process exited with error code 100
Unforunately that can be a common error in protractor for syntax issues. It's hard to tell without code indentation, but the error is about a missing ) and at a quick glance it looks like you are missing one in your final expect statement.
You have:
expect(elhHomepage.getgreetingText().toEqual('Hello lease');
It should be:
expect(elhHomepage.getgreetingText()).toEqual('Hello lease');
You can use linters like ES Lint to quickly find syntax errors like this.

Use of Expected Conditions on Non Angular Site with Protractor Leads to "Type Error: Cannot read property 'bind' of undefined"

I am seeing following issue when I am using Expected Conditions on webelements returned through element object of Protractor. I tried with $ as well, that resulted in the same thing. I am using Protractor 3.1.1 on Node 4.2.4, Chrome V47.*
"Type Error: Cannot read property 'bind' of undefined"
Before asking, I searched the forums, and understood there are some known issues with using Expected Conditions with selenium elements using driver.findElement.
However, I could not come across a similar issues reported while using element object itself.
https://github.com/angular/protractor/issues/1853
We have a non angular app for login page, which will be switched to Angular, post login. So, I have set ignoreSynchronization=true and later planned to reset it to false after login. Below is the sample code, appreciate any thoughts from community.
Page Objects File
module.exports = {
login: element(by.model('credentials.username')),
password: element(by.model('credentials.password')),
user: "Email",
passwd: "Password",
goButton: $('input.btn.btn-primary'),
EC: protractor.ExpectedConditions,
go: function() {
browser.get("Application URL",30000);
browser.wait(this.EC.elementToBeClickable(this.login),30000);
},
Below is my Sample Test Suite
var VMPage = require('./LoginPage.js');
describe('App Demo', function() {
beforeEach(function() {
console.log("Before Each Started");
browser.driver.manage().timeouts().implicitlyWait(30000);
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1800000;
browser.ignoreSynchronization = true;
VMPage.go();
VMPage.login();
});
it('Test Case', function() {
console.log("***Test Started***");
});
});
Stack trace reported looks as follows:
Stack:
TypeError: Cannot read property 'bind' of undefined
at [object Object].ExpectedConditions.presenceOf (C:\Users\PJ\Ap
pData\Roaming\npm\node_modules\protractor\lib\expectedConditions.js:289:33)
at [object Object].ExpectedConditions.visibilityOf (C:\Users\PJ\
AppData\Roaming\npm\node_modules\protractor\lib\expectedConditions.js:328:10)
at [object Object].ExpectedConditions.elementToBeClickable (C:\Users\PJ0
0366401\AppData\Roaming\npm\node_modules\protractor\lib\expectedConditions.js:17
8:12)
at Object.module.exports.go (D:\protractor_git\Demo\\Log
inPage.js:14:24)
at Object.<anonymous> (D:\protractor_git\Demo\\LoginTest
.js:9:10)
at C:\Users\PJ\AppData\Roaming\npm\node_modules\protractor\node_
modules\jasminewd2\index.js:96:23
at new wrappedCtr (C:\Users\PJ\AppData\Roaming\npm\node_modules\
protractor\node_modules\selenium-webdriver\lib\goog\base.js:2468:26)
at controlFlowExecute (C:\Users\PJ\AppData\Roaming\npm\node_modu
les\protractor\node_modules\jasminewd2\index.js:82:18)
From: Task: Run beforeEach in control flow
at Object.<anonymous> (C:\Users\PJ\AppData\Roaming\npm\node_modu
les\protractor\node_modules\jasminewd2\index.js:81:14)
at attemptAsync (C:\Users\PJ\AppData\Roaming\npm\node_modules\pr
otractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasmine
.js:1916:24)
at QueueRunner.run (C:\Users\PJ\AppData\Roaming\npm\node_modules
\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasm
ine.js:1871:9)
at QueueRunner.execute (C:\Users\PJ\AppData\Roaming\npm\node_mod
ules\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\
jasmine.js:1859:10)
at Spec.Env.queueRunnerFactory (C:\Users\PJ\AppData\Roaming\npm\
node_modules\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmi
ne-core\jasmine.js:697:35)
at Spec.execute (C:\Users\PJ\AppData\Roaming\npm\node_modules\pr
otractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasmine
.js:359:10)
at Object.fn (C:\Users\PJ\AppData\Roaming\npm\node_modules\protr
actor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasmine.js
:2479:37)
at attemptAsync (C:\Users\PJ\AppData\Roaming\npm\node_modules\pr
otractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasmine
.js:1916:24)
at QueueRunner.run (C:\Users\PJ\AppData\Roaming\npm\node_modules
\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasm
ine.js:1871:9)
at QueueRunner.execute (C:\Users\PJ\AppData\Roaming\npm\node_mod
ules\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\
jasmine.js:1859:10)
From asynchronous test:
Error
at Suite.<anonymous> (D:\protractor_git\Demo\\LoginTest.
js:3:2)
at addSpecsToSuite (C:\Users\PJ\AppData\Roaming\npm\node_modules
\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasm
ine.js:833:25)
at Env.describe (C:\Users\PJ\AppData\Roaming\npm\node_modules\pr
otractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine-core\jasmine
.js:802:7)
at jasmineInterface.describe (C:\Users\PJ\AppData\Roaming\npm\no
de_modules\protractor\node_modules\jasmine\node_modules\jasmine-core\lib\jasmine
-core\jasmine.js:3375:18)
at Object.<anonymous> (D:\protractor_git\Demo\\LoginTest
.js:2:1)
Your page object should be defined as a function:
var Page = function () {
this.login = element(by.model('credentials.username'));
this.password = element(by.model('credentials.password'));
this.user = "Email";
this.passwd = "Password";
this.goButton = $('input.btn.btn-primary');
this.EC = protractor.ExpectedConditions;
this.go = function() {
browser.get("Application URL", 30000);
browser.wait(this.EC.elementToBeClickable(this.login), 30000);
};
};
module.exports = new Page();
Thanks for the suggestion, I agree it should work the way you mentioned, however, it’s strange that we still get into unrecognized types issue.
We are a bit new to the node js and this stack. I tried multiple options including the one you mentioned, by wrapping everything into a function, by individually exposing the elements/functions as module exports etc..
Finally, I found the following one to be working for me, using prototyping.
var AngularPage = function () {
};
AngularPage.prototype.login = element(by.model('credentials.username'));
AngularPage.prototype.password = element(by.model('credentials.password'));
AngularPage.prototype.goButton = $('input.btn.btn-primary');
AngularPage.prototype.user = "username";
AngularPage.prototype.passwd = "password";
AngularPage.prototype.EC = protractor.ExpectedConditions;
AngularPage.prototype.go = function(){
browser.get("Application URL",30000)
.then(browser.wait(this.EC.elementToBeClickable(this.login),30000));
expect(browser.getTitle()).toContain(‘String’);
};
AngularPage.prototype.loginMethod = function(){
console.log("Login started");
this.login.sendKeys(this.user);
this.password.sendKeys(this.passwd);
this.goButton.click();
browser.wait(this.EC.elementToBeClickable(this.compute));
};
module.exports = AngularPage;
In the test file, this is how, I was able to import and call it, a sample snippet.
var page = require('./LoginPage_Export_As_Prototype.js');
var LoginPage = new page();
LoginPage.go();
LoginPage.loginMethod();
Thanks,
Prakash

Unknown provider error when injecting factory

I am using yeoman angular full stack generator. Trying out ToDo items tutorial with MongoDB.
Everything worked fine i.e. I was able to read from DB using $http.get. However I decided to go further and create a factory so I can perform CURD.
After creating factory I tried to inject it but getting error as follows:
Error: [$injector:unpr] Unknown provider: factToDoProvider <- factToDo
http://errors.angularjs.org/1.2.6/$injector/unpr?p0=factToDoProvider%20%3C-NaNactToDo
at http://localhost:9000/bower_components/angular/angular.js:78:12
at http://localhost:9000/bower_components/angular/angular.js:3538:19
at Object.getService [as get] (http://localhost:9000/bower_components/angular/angular.js:3665:39)
at http://localhost:9000/bower_components/angular/angular.js:3543:45
at getService (http://localhost:9000/bower_components/angular/angular.js:3665:39)
at invoke (http://localhost:9000/bower_components/angular/angular.js:3687:13)
at Object.instantiate (http://localhost:9000/bower_components/angular/angular.js:3708:23)
at http://localhost:9000/bower_components/angular/angular.js:6758:28
at link (http://localhost:9000/bower_components/angular-route/angular-route.js:897:26)
at nodeLinkFn (http://localhost:9000/bower_components/angular/angular.js:6212:13)
Main.js controller looks like
'use strict';
angular.module('angularFsApp')
.controller('MainCtrl', function ($scope, $http, factToDo) {
$http.get('/api/awesomeThings').success(function(awesomeThings) {
$scope.awesomeThings = awesomeThings;
});
$http.get('/todo/todoItems').success(function(todoItems) {
$scope.todoItems = todoItems;
});
//$scope.newtodoItems = factToDo.getAllItems();
});
Where factToDo is my factory which look like as follows (todo.js)
angular.module('angularFsApp')
.factory('factToDo', function() {
return {
getAllItems: function () {
return [
{description: 'Hello World 1', priority: '15'},
{description: 'Hello World 2', priority: '15'},
{description: 'Love for all', priority: '1500'}
];
}
}
});
I tried by changing my code in main.js as described in AngularJS error ref as follows
angular.module('angularFsApp')
.controller('MainCtrl', ['$scope', '$http', 'factToDo', function ($scope, $http, factToDo) {
as well as I tried Dan Wahlin but i got same issue.
Make sure the file with the 'factToDo' is included into your app.
For a convenient development and to avoid issues like this in the future try the Grunt task runner to concatenate all your code for you and include it as a one file.
This tutorial seems to be sufficient for starting with Grunt and file concatenation.