Protractor POM method is not recognizing - protractor

spec.js
describe('Testing an animal adoption flow using page object', function() {
beforeEach(function() {
browser.get('http://www.thetestroom.com/jswebapp/index.html');
});
var home_page = require('./pages/home_page.js');
it ('Should be able to adopt an animal by page object', function() {
home_page.enterName('Blabla');
expect(home_page.getDynamicText()).toBe('Blabla');
var animal_page = home_page.clickContinue();
animal_page.selectAnimal(1);
var confirm_page = animal_page.clickContinue();
expect(confirm_page.getTitle()).toContain('Thank');
});
});
home_page.js
require('./animal_page.js');
var home_page = function() {
this.nameTextBox = element(by.model('person.name'));
this.dynamicText = element(by.binding('person.name'));
this.continueButton = element(by.buttonText('CONTINUE'));
this.enterName = function(name) {
this.nameTextBox.sendKeys(name);
};
this.getDynamicText = function() {
return this.dynamicText.getText();
};
this.clickContinue = function() {
this.continueButton.click();
return require('./animal_page.js');
};
};
Failures:
Testing an animal adoption flow using page object Should be able to adopt an animal by page object
Message:
[31m Failed: home_page.enterName is not a function[0m
Stack:
TypeError: home_page.enterName is not a function

You don't create an instance of your constructor function with new keyword. It should have been
var home_page = new (require('./pages/home_page.js'));
and you need to instruct js what you are exporting, so your home page should be
require('./animal_page.js');
var home_page = function() {
this.nameTextBox = element(by.model('person.name'));
this.dynamicText = element(by.binding('person.name'));
this.continueButton = element(by.buttonText('CONTINUE'));
this.enterName = function(name) {
this.nameTextBox.sendKeys(name);
};
this.getDynamicText = function() {
return this.dynamicText.getText();
};
this.clickContinue = function() {
this.continueButton.click();
return require('./animal_page.js');
};
}
module.exports = home_page; // <------ this line
but make sure you do the same with animal_page

I got the answer, we need to include
spec.js
const { browser } = require('protractor');
home_page.js
module.exports = new home_page();

Related

Unable to use page objects in my spec file in protractor

//This is my AngularPage.cs page object file
var AngularPage= function()
{
var nameInput= element(by.model('yourName'));
var greeting = element(by.binding('yourName'));
this.get=function()
{
browser.get('http://www.angularjs.org');
};
this.setName= function(name)
{
nameInput.sendKeys(name);
};
this.getGreeting= function()
{
return greeting.getText();`
};
};
module.exports = new AngularPage();
//This is my AngularHome_spec.js file
var angularPage = require('./AngularPage.js');
describe('angularjs homepage',function()
{
var angular_page;
beforeEach(function()
{
angular_page= new AngularPage();
});
it('greetings for new user', function()
{
// var angular_page= new AngularPage();
angular_page.get();
angular_page.setName('Rahul');
expect(angular_page.getGreeting()).toEqual('Hello Rahul!');
}
);
}
);
//I am unable to use page objects in my spec file as it is throwing an error
:AngularPage is not defined
In your code, object has been created twice. First time on page "AngularPage.js" and second time on spec "AngularHome_spec.js" level.
Do following on page "AngularHome_spec.js"
module.exports = AngularPage;
Change the
var AngularPage = require('./AngularPage.js');//Capital the 'A'

Use Protractor browser.driver as a variable

I'm using page object model and I'm stuck at how to put the browser.driver elements as a variable.
Here is an example of using it with Protractor's element:
var Messages = function() {};
var messagesLink = element(by.css('a[href*="/Messages"]'));
Messages.prototype.visitPage = function() {
messagesLink.click();
};
exports.Messages = new Messages();
Then I can use Messages.visitPage(); throughout my test. The problem is when I try to do the same thing with browser.driver:
var Login = function() {};
var usernameField = browser.driver.findElement(by.id('UserName'));
var passwordField = browser.driver.findElement(by.id('Password'));
var signOnButton = browser.driver.findElement(by.css('input[value="Sign On"]'));
var registeredUserName = 'user';
var registeredUserPass = 'pass';
Login.prototype.loginAsRegisteredUser = function() {
loginAs(registeredUserName, registeredUserPass);
};
var loginAs = function(userName, pass) {
usernameField.sendKeys(userName);
passwordField.sendKeys(pass);
signOnButton.click();
};
exports.Login = new Login();
The test instantly fails before even starting, throwing this error NoSuchElementError: Unable to locate element: *[id="UserName"]. The reason why I'm using browser.driver is because I'm accessing elements on a non-angular page. I want to try and keep angular and non-angular references separate from each other.
I'm not sure how Protractor handles this but in Selenium I can use the variable like so, static By cancelButton = By.id("cphMain_btnCancel");.
So, is there anyway that this can be done using Protractor?
Spec File:
var home = require('../../pages/home/Home.js').Home;
var headerHome = require('../../pages/home/HeaderHome.js').HeaderHome;
var login = require('../../pages/Login.js').Login;
describe('Registered User | DEV_Smoke |--- Home page: ', function() {
it('Navigates to the Home page', function() {
home.visitPage();
});
it('Prints the current URL (see build.log)', function() {
home.verifyHomeUrl();
});
it('Clicks Sign On link and signs in as a registered user', function() {
headerHome.clickSignOnLink();
login.loginAsRegisteredUser();
});
});
Easiest way would be to just wrap the findElement in functions and call them as needed
var Login = function() {};
var usernameField = function() {
return browser.driver.findElement(by.id('UserName')); //returns promise
}
var passwordField = function() {
return browser.driver.findElement(by.id('Password'));
}
var signOnButton = function() {
return browser.driver.findElement(by.css('input[value="Sign On"]'));
}
var registeredUserName = 'user';
var registeredUserPass = 'pass';
Login.prototype.loginAsRegisteredUser = function() {
loginAs(registeredUserName, registeredUserPass);
};
var loginAs = function(userName, pass) {
usernameField().sendKeys(userName);
passwordField().sendKeys(pass);
signOnButton().click();
};
exports.Login = new Login();
browser.driver is of type Webdriver and when calling findElement, selenium-webdriver will try to evaluate wherever it is stated in your code. So prior to your login method and possibly navigation to the login page, you are automatically looking for the WebElements for UserName, Password, and input[value="SignOn"].
In your code snippet, it looks like you should use element. When using element, at runtime, the findElement will be evaluated. This allows for more reusable code.
For non-angular pages, you might have to provide your own syncing or some arbitrary sleep. This usually occurs with animations, long load screens, etc.
Also make sure you return your promises so the jasmine wrapper evaluates your function properly.
var usernameField = element(by.id('UserName'));
var passwordField = element(by.id('Password'));
var signOnButton = element(by.css('input[value="Sign On"]'));
// make sure you return your promises so the jasmine wrapper
// evaluates your function properly.
var loginAs = function(userName, pass) {
return usernameField.sendKeys(userName).then(() => {
return passwordField.sendKeys(pass).then(() => {
return signOnButton.click();
});
});
};

Mapping List with Knockout Mapping

I have created view model
var catalog = ko.observableArray();
$.ajax({
type: "GET",
url: "http://localhost:8080/ticket-service/rest/ticket/list",
success: function(msg) {
catalog.push.apply(catalog, $.map(msg, function(data) {
return new Ticket(data)
}));
return catalog;
},
error: function(msg) {
console.log(msg)
}
});
and the model
function Ticket(data) {
this.ticketId = ko.observable(data.ticketId);
this.ticketNo = ko.observable(data.ticketNo);
this.ticketTitle = ko.observable(data.ticketTitle);
this.longDescription = ko.observable(data.longDescription);
this.createdBy = ko.observable(data.createdBy);
this.createdOn= ko.observable(data.createdOn);
this.assignTo = ko.observable(data.assignTo);
this.priority = ko.observable(data.priority);
this.dueDate = ko.observable(data.dueDate);
this.status = ko.observable(data.status);
this.projectId = ko.observable(data.projectId);
}
with at the end viewmodel like this
return {
ticket: newTicket,
searchTerm: searchTerm,
catalog: filteredCatalog,
newTicket: newTicket,
addTicket: addTicket,
delTicket: delTicket
};
})();
console.log(vm);
ko.applyBindings(vm);
produce list,add, and delete form.The question is how can i use knockout mapping that can list from get methode.
you need to do something like this
Demonstrated taking a single entity from your code .
view:
Output Preview :
<pre data-bind="text:ko.toJSON($data,null,2)"></pre>
viewModel:
function Ticket(data) {
this.ticketId = ko.observable(data.ticketId);
}
var mapping = {
create: function (options) {
return new Ticket(options.data);
}
};
var ViewModel = function () {
var self = this;
self.catalog = ko.observableArray();
var data = [{
'ticketId': 1
}, {
'ticketId': 2
}]
//under ajax call do the same but pass 'msg' in place of data
self.catalog(ko.mapping.fromJS(data, mapping)())
console.log(self.catalog()); // check console for output
};
ko.applyBindings(new ViewModel());
sample working fiddle here

KnockoutJS : initial values are not posted to server when using ko.toJSON(this)?

I've this javascript viewmodel defined:
function PersonViewModel() {
// Data members
this.Name = ko.observable();
this.Function_Id = ko.observable();
this.SubFunction_Id = ko.observable();
this.Functions = ko.observableArray();
this.SubFunctions = ko.observableArray();
// Whenever the Function changes, update the SubFunctions selection
this.Function_Id.subscribe(function (id) {
this.GetSubFunctions(id);
}, this);
// Functions to get data from server
this.Init = function () {
this.GetFunctions();
this.Function_Id('#(Model.Function_Id)');
};
this.GetFunctions = function () {
var vm = this;
$.getJSON(
'#Url.Action("GetFunctions", "Function")',
function (data) {
vm.Functions(data);
}
);
};
this.GetSubFunctions = function (Function_Id) {
var vm = this;
if (Function_Id != null) {
$.getJSON(
'#Url.Action("GetSubFunctions", "Function")',
{ Function_Id: Function_Id },
function (data) {
vm.SubFunctions(data);
}
);
}
else {
vm.SubFunction_Id(0);
vm.SubFunctions([]);
}
};
this.Save = function () {
var PostData = ko.toJSON(this);
var d = $.dump(PostData);
alert(d);
$.ajax({
type: 'POST',
url: '/Person/Save',
data: PostData,
contentType: 'application/json',
success: function (data) {
alert(data);
}
});
};
}
$(document).ready(function () {
var personViewModel = new PersonViewModel();
personViewModel.Init();
ko.applyBindings(personViewModel);
});
When the Submit button is clicked, the data from the select lists is posted, but NOT the 'Function_Id'.
When I choose a different value in the Function dropdown list, and the click the Submit button, the value for 'Function_Id' is correctly posted.
How to fix this ?
It's because the scope of the this keyword in javascript
this.Init = function () {
this.GetFunctions(); // this === PersonViewModel.Init
this.Function_Id('#(Model.Function_Id)'); // calls PersonViewModel.Init.Function_Id(...)
};
You should store the refrence to the PersonViewModel instance.
var self = this;
self.Init = function () {
self.GetFunctions();
self.Function_Id('#(Model.Function_Id)'); // calls PersonViewModel.Function_Id(...)
};

how do i make a jquery plugin

I'm trying to make a jquery plugin
but it's not working what a'm i doing wrong
(function($){
$.fn.rss({
//pass the options variable to the function
rss: function(options) {
//Set the default values, use comma to separate the settings, example:
var defaults = {
feedUrl: ''
}
var options = $.extend(defaults, options);
return this.each(function() {
var Setting = options;
//code to be inserted here
$.ajax({
type: "GET",
url: Setting.feedUrl,
dataType: "xml",
success: function(xml) {
$(xml).find('channel').each(function(){
$(xml).find('image').each(function(){
var title2 = $(this).find('title').text();
var url2 = $(this).find('link').text();
$('<div class="title"></div>').html(''+title2+'').fadeIn(1000).appendTo('#title');
});
$(xml).find('item').each(function(){
var title = $(this).find('title').text();
var brief = $(this).find('description').text();
var url = $(this).find('link').text();
$('<div class="items"></div>').html('<div class="dis">'+brief+'</div>').fadeIn(1000).appendTo('#blab');
});
});
}
});
});
}
});
})(jQuery)
By writing $.fn.rss(...), you're calling a non-existent function.
You need to create a function by writing
$.fn.rss = function(...) { ... };