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();
});
});
});
Related
I am trying to scrape the href attribute value from all the video links on youtube page after I pass a search query.
var casper = require('casper').create();
var links;
function getLinks() {
var links = document.querySelectorAll('div#contents div#dismissable a#thumbnail');
return Array.prototype.map.call(links, function (e) {
return e.getAttribute('href')
});
}
casper.start('https://www.youtube.com/results?search_query=a');
casper.then(function () {
links = this.evaluate(getLinks);
});
casper.run(function () {
for(var i in links) {
console.log(links[i]);
}
casper.done();
});
Also is
div#contents div#dismissable a#thumbnail
the correct path to scrape the href attribute of each a tag of the video.
when i run this code i get an error saying
TypeError: undefined is not a constructor (evaluating 'casper.done()')
C:/Users/rohit/Desktop/scraping codes/phantomjs:/code/test.js:24
C:/Users/rohit/Desktop/scraping codes/phantomjs:/platform/casper.js:423 in checkStep
I'm not sure if this line:
casper.then(function () {
links = this.evaluate(getLinks);
});
Should be
casper.then(function () {
links = this.evaluate(getLinks());
});
or
casper.then(function () {
links = this.evaluate(function(){
getLinks();
});
});
casper.done(); is obsolete and is not necessary in scripts anymore, see the issue, just remove it from the script.
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();
...
I'm having some trouble testing angular directives. Here's what I'm experiencing. I've got karma set up to run my tests. It appears that the link code within the directive (the section with console log "kicking off calculations") never actually fires. I'm not sure what I'm doing wrong. The test works as I'd expect -- except when I get down to imageNode.style -- there's nothing in there. There are no styles assigned to the image. Why is the directive code not being fired? Any ideas?
This is my module code.
(function() {
'use strict';
// sets narrower side of image to width of parent div
// used in sjwUserImage
angular.module('sjw.util', [])
.directive('imgFit', function() {
return {
restrict: 'A',
link: function(scope, element, attr) {
element.bind('load', function(e) {
console.log('kicking off calculations...');
console.log(element);
var parentWidth = element.parent().width();
if (this.naturalHeight > this.naturalWidth) {
// not horizontal or square
this.width = parentWidth;
}
else {
this.height = parentWidth;
}
});
}
};
});
})();
This is my test code.
describe('imgFit directive', function() {
var compile;
var scope;
var directiveElem;
console.log('loading sjw.util module...');
beforeEach(function(done) {
module('sjw.util', function() {
console.log('completed loading module.');
});
inject(function($compile, $rootScope) {
angular.module('sjw.util');
compile = $compile;
scope = $rootScope.$new();
directiveElem = getCompiledElement();
done();
});
});
function getCompiledElement() {
var myApp = angular.module('sjw.util');
var elem = angular.element(
'<div style="height:35px;width:35px">' +
'<img ' +
'ng-src="http://random_image_url" img-fit>' +
'</div>' +
'<div style="height:35px;width:35px">' +
'<img ' +
'ng-src="http://random_image_url" img-fit>' +
'</div>');
var compiledDirective = compile(elem)(scope);
scope.$digest();
return compiledDirective;
}
it('should assign width to parent width when image is square', function() {
var squareImageParent = directiveElem[0];
console.log(directiveElem);
expect(squareImageParent).not.toBe(null);
var imageNode = squareImageParent.childNodes[0];
expect(imageNode).toBeDefined();
console.log(imageNode);
console.log(imageNode.style);
//expect(imageNode.style.height == '35px').toBe(true);
});
});
I have exorcised this demon. My problem was with the directive itself. My images weren't finishing loading within the headless browser I'm using. So the 'load' event in 'imgFit.link' would never fire. Obviously a problem. That's why inserting my timeout (in comment above) was helping. It allowed the images to finish loading. Ugly hack, but seems like I have no way of knowing when phantom's going to load the images.
beforeEach(function(done) {
module('sjw.util');
inject(function($compile, $rootScope) {
compile = $compile;
scope = $rootScope.$new();
directiveElem = getCompiledElement();
// wait for the images to finish loading.
setTimeout(done, 2000);
});
});
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.
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);