Protractor tests inconsistently passing / failing - javascript

The problem that I have with this test is that sometimes it passes, sometimes it fails, and when it does the latter a "Failed: No element found using locator: By(css selector, .add.create_ServiceOrders)" message appears in the console. Idk what to do to fix it :(
describe('angularjs homepage', function() {
it('should greet the named user', function() {
//browser.ignoreSynchronization = true
browser.get('https://int.m-tech.com/hotsosmobile/app/Index?/login#/login');
browser.waitForAngular();
var input = element(by.model('loginInfo.login'));
input.sendKeys('xxx');
expect(input.getAttribute('value')).toBe('xxx');
var input = element(by.model('loginInfo.password'));
input.sendKeys('yyy');
expect(input.getAttribute('value')).toBe('yyy');
browser.waitForAngular();
browser.driver.actions().sendKeys(protractor.Key.ENTER).perform();
browser.waitForAngular();
var AddButton = element(by.css(".add.create_ServiceOrders" ));
browser.actions().mouseDown(AddButton).mouseUp().perform();
browser.actions().mouseMove(AddButton).click().perform();
browser.waitForAngular();
var AddButton = element(by.css(".icon-standard-issue-floors" ));
browser.actions().mouseDown(AddButton).mouseUp().perform();
browser.actions().mouseMove(AddButton).click().perform();
browser.waitForAngular();
.....
});
});

Base on my experience, I usually do separate it in another it function something like this.
var AddButton = element(by.css(".add.create_ServiceOrders" ));
it ( 'should pass', function () {
browser.actions().mouseDown(AddButton).mouseUp().perform();
});
it ( 'should pass', function () {
browser.actions().mouseMove(AddButton).click().perform();
});

You need to wait for element to be ready, before manipulating. Try this:
var AddButton = $(".add.create_ServiceOrders");
browser.wait(protractor.ExpectedConditions.visibilityOf(AddButton), 5000, 'Button should be visible');
browser.actions().mouseDown(AddButton).mouseUp().perform();
browser.actions().mouseMove(AddButton).click().perform();
...

Related

Jasmine Dom element test

I'm new to writing tests and I'm trying to figure out how to test if after a click the right content is loaded. I'm testing a directive, but the loaded content in the center panel. I'm first firing a click event and then I try to compile the loaded content and check if the title is the one I expected (Test).
What I'm getting as an error is
"Cannot read property 'innerHTML' of undefined"
Any idea why and how to fix the test?
describe('someSelector', function () {
beforeEach(function () {
module(function($provide) {
$provide.decorator('$timeout', function($delegate) {
var flush = $delegate.flush;
var $timeout = jasmine.createSpy('$timeout').and.callFake($delegate);
$timeout.flush = flush;
return $timeout;
});
});
this.injectDependencies('$compile',
'$scope',
'$httpBackend',
'renderTemplateAndAppendToDom',
'renderTemplate',
'$timeout');
this.render = this.renderTemplateAndAppendToDom;
this.dirStr = '<div class="some-navigator" vx-view="history[history.currentIndex].naviView"></div>';
this.viewStr = '<center-panel></center-panel>';
});
describe('when navigating to an object', function () {
beforeEach(function () {
this.$httpBackend.resetExpectations();
});
it('should load the correct content', function () {
var dir = this.$compile(this.dirStr)(this.$scope);
dir.find('span.some-navigator-label [title="Test"]').click();
dir.remove();
var view = this.$compile(this.viewStr)(this.$scope);
var contentCheck = view.find('span.titlebar-text');
expect(contentCheck[0].innerHTML).toEqual('Test');
this.$scope.$destroy();
view.remove();
});
});
});

Mocha Chai wait for modal to show

How can I ask mocha/chai to wait for a modal to be shown before it expects the test to be complete?
I am wrapping bootstrap modal and emitting my own events. show works fine, but I need to wait for the modal to be shown for my next test. I can't get done() to work at all.
describe("Modal", function() {
describe("wrapModalEvents", function() {
it("should wrap the show.bs.modal event", function() {
var m = new Modal();
m.wrapModalEvents();
var res = {e:1};
m.on('show', function(){
res.e = 555;
});
m.modal();
expect(res.e).to.equal(555);
});
it("should wrap the shown.bs.modal event", function() {
var m = new Modal();
m.wrapModalEvents();
var res = {e:1};
m.on('shown', function(){
res.e = 123;
});
// need to wait at least one second
expect(res.e).to.equal(123);
});
});
});

Protractor can't find gmail input with id of password

I'm trying to set up Protractor for testing my application but it requires auth through gmail, and I'm stuck on trying to login:
describe('Vivace Home page', function() {
var hasClass = function (element, cls) {
return element.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(cls) !== -1;
});
};
beforeEach(function() {
browser.ignoreSynchronization = true;
browser.get('/');
var emailInput = browser.driver.findElement(by.id('Email'));
emailInput.sendKeys('paulG#gmail.com')
var nextButton = browser.driver.findElement(by.id('next'));
nextButton.click().then(function() {
browser.pause();
var passwordInput = browser.driver.findElement(by.id('Passwd'));
console.log(passwordInput);
passwordInput.sendKeys('11111');
// var signInButton = browser.driver.findElement(by.id('signIn'));
})
});
it('should have the correct title', function() {
expect(browser.getTitle()).toEqual('InRhythm - Vivace');
});
});
I can see Protractor opening up the gmail page, inputting the email and clicking the next button, and when I do browser.pause I can actually see the password input with an id of "Passwd" right there on the page with inspector and yet I can't access it to complete my log in.
I get this error when I remove the browser.pause
Failed: no such element: Unable to locate element: {"method":"id","selector":"Passwd"}
Wait for it to become visible:
var EC = protractor.ExpectedConditions;
var passwordInput = element(by.id('Passwd'));
browser.wait(EC.visibilityOf(passwordInput), 5000);
passwordInput.sendKeys('11111');

Function stopped working after Protractor PageObject implementation

I've got a problem with executing multiple tests(i've got two here). It seems like function deleteOneTask() stopped working and my tests started to fail each other. Before i started to use PageObject everything was ok.
Stacktrace:
TypeError: Cannot read property 'click' of undefined
at c:\Users\Денис\WebstormProjects\ProtractorTest\pages\angular.page.js:29:30
It refers to this line: this.deleteButton.click();
Here is my spec.js
'use strict';
var todoAppPage = require('../pages/angular.page');
describe('angularjs todo list', function () {
var page;
beforeEach(function () {
page = new todoAppPage();
page.get();
});
it('should add a todo task', function () {
page.addNewTask('my first task');
expect(page.todoList.count()).toEqual(1);
expect(page.todoList.get(0).getText()).toEqual('my first task');
page.deleteOneTask(); //here it won't work
});
it('should show correct number of undone tasks', function () {
page.addNewTask('my first task');
expect((page.counter).getText()).toEqual('1');
page.deleteOneTask(); //here it won't work
});
it('should show correct number of undone tasks2', function () {
var deleteButton = element.all(by.className('destroy')).get(0);
var viewArea = element(by.model('todo.completed'));
page.addNewTask('my first task');
expect((page.counter).getText()).toEqual('1');
element(by.id('footer')).element(by.linkText('All')).click();
browser.driver.actions().mouseMove(viewArea).perform().then(function () { //hover and delete single task
deleteButton.click();
});; //here it will work
});
});
Here is Page Object file
'use strict';
var todoAppPage = function() {
this.newTodo = element(by.model('newTodo'));
this.todoList = element.all(by.repeater('todo in todos'));
this.viewArea = element(by.model('todo.completed'));
this.deleteButton = element.all(by.className('destroy')).get(0);
this.categoryAll = element(by.id('footer')).element(by.linkText('All'));
this.counter = element(by.id('todo-count')).element(by.className('ng-binding'));
this.get = function() {
browser.get('#/');
};
this.addNewTask = function (taskName) {
this.newTodo.sendKeys(taskName);
this.newTodo.sendKeys(protractor.Key.ENTER);
};
this.deleteOneTask = function () {
this.categoryAll.click(); //go to 'All' category
browser.driver.actions().mouseMove(this.viewArea).perform().then(function () { //hover and delete single task
this.deleteButton.click();
});
};
};
module.exports = todoAppPage;
As mentioned in a comment, using a that = this will solve your problem. Eg.
this.deleteOneTask = function () {
var that = this;
this.categoryAll.click(); //go to 'All' category
browser.driver.actions().mouseMove(this.viewArea).perform().then(function () { //hover and delete single task
that.deleteButton.click();
});
That's the best solution I've seen but I'd be happy to see a better one too.

How to test if method has been called only once and not the second time in Jasmine?

I am testing mechanism that should call method once and prevent any subsequent calls with jasmine, I can see by attaching breakpoints that method is NOT being called second time however jasmine test fails. I would assume it has to do with spy not being designed to be used for multiple checks.
What would be proper solution to given situation?
JSfiddle of Code that is being tested I could not figure out how to do jasmine test jsfiddle properly (Jasmine version I am using is 1.3.1 while test template is on 1.2.0).
Test looks like this:
it("Invoking OnPreQuery will add event listener for OnTheMoveViewPreLoad event. Triggering OnTheMoveViewPreLoad twice will call getChildrenForMasterRecordList only first time", function () {
AddTreeSettingsObjectToBC({ bc: bc, Tree: { IncludeChildren: true} });
ComposeMockPageObjWithObservableFieldsWithChildren();
var preQuerySpy = spyOnEvent(onTheMove.PageDataRoles, 'OnPreQuery');
$(onTheMove.PageDataRoles).trigger('OnPreQuery', { knockoutContextName: 'bc' });
expect('OnPreQuery').toHaveBeenTriggeredOn(onTheMove.PageDataRoles);
expect(preQuerySpy).toHaveBeenTriggered();
var getChildrenForMasterRecordListSpy = spyOn(window, 'getChildrenForMasterRecordList');
$(onTheMove.PageDataRoles).trigger('OnTheMoveViewPreLoad', { knockoutContextName: 'bc' });
expect(getChildrenForMasterRecordListSpy).toHaveBeenCalled();
$(onTheMove.PageDataRoles).trigger('OnTheMoveViewPreLoad', { knockoutContextName: 'bc' });
expect(getChildrenForMasterRecordListSpy).not.toHaveBeenCalled();
});
Code that is being tested:
HTML
<div data-role="page"></div>
Javascript
var onTheMove = function(){};
$.extend(onTheMove,{
NullValue : "null",
PageDataRoles : 'div[data-role="page"], div[data-role="dialog"]',
OnTheMovePrefix : 'OnTheMove_'
});
$(document).on('OnPreQuery', onTheMove.PageDataRoles, function (e, options) {
var isChildAttachmentQueued = true;
var knockoutContextName = options.knockoutContextName;
if (TreeEnabled(knockoutContextName)) {
var isModelReadyToAttachChildren = function () {
var isReady = false;
if (PageObj[knockoutContextName] != undefined) {
isReady = (PageObj[knockoutContextName]().length > 0) && isChildAttachmentQueued;
}
return isReady;
};
var treeSettings = eval(knockoutContextName).Tree;
treeSettings.knockoutContextName = knockoutContextName;
$(onTheMove.PageDataRoles).on('OnTheMoveViewPreLoad', function (e, options) {
if (isModelReadyToAttachChildren()) {
getChildrenForMasterRecordList({
parentTable: eval(knockoutContextName).primaryTableName,
knockoutContextName: treeSettings.knockoutContextName,
parentIdColumn: treeSettings.ParentIdColumn,
masterIdColumn: treeSettings.MasterIdColumn
});
isChildAttachmentQueued = false;
}
});
}
});
function getChildrenForMasterRecordList(options) {
console.log('beep');
}
toHaveBeenCalledTimes(1)
now makes this much easier.
expect(yourSpy).toHaveBeenCalledTimes(1);
Figured it out myself, spy has property callCount that auto-increments by one on each call.
it("Invoking OnPreQuery will add event listener for OnTheMoveViewPreLoad event. Triggering OnTheMoveViewPreLoad twice will call getChildrenForMasterRecordList only first time", function () {
AddTreeSettingsObjectToBC({ bc: bc, Tree: { IncludeChildren: true} });
ComposeMockPageObjWithObservableFieldsWithChildren();
var preQuerySpy = spyOnEvent(onTheMove.PageDataRoles, 'OnPreQuery');
$(onTheMove.PageDataRoles).trigger('OnPreQuery', { knockoutContextName: 'bc' });
expect('OnPreQuery').toHaveBeenTriggeredOn(onTheMove.PageDataRoles);
expect(preQuerySpy).toHaveBeenTriggered();
var getChildrenForMasterRecordListSpy = spyOn(window, 'getChildrenForMasterRecordList');
$(onTheMove.PageDataRoles).trigger('OnTheMoveViewPreLoad', { knockoutContextName: 'bc' });
expect(getChildrenForMasterRecordListSpy).toHaveBeenCalled();
$(onTheMove.PageDataRoles).trigger('OnTheMoveViewPreLoad', { knockoutContextName: 'bc' });
expect(getChildrenForMasterRecordListSpy.callCount).toEqual(1);
});
as per comment
in Jasmine 2.0 its
expect(object.func.calls.count()).toBe(1);

Categories