For purpose of testing I am using multiple files. Each one represent one part of website for test.
In one of start test file I create variabile for name of new case, it looks like:
var moment = require('../../../../../node_modules/moment');
describe('Create new case', function() {
var caseNumber = moment().format('YYYYMMDD-HHmmss-SS');
But somewhere at the end of all (in another test file) I would like to use this caseNumber again (exactly same as was used in first test, not generate new one).
Can anyone advise me how can I do it in protractor?
It doesn't sound quite right to have one test depending on an another test to define and export a variable. Set the global variable inside onPrepare() using global:
onPrepare: function() {
global.caseNumber = moment().format('YYYYMMDD-HHmmss-SS');
},
Then, you'll have caseNumber as a global variable across all the tests.
There's no need to use globals. You can make it more readable by creating your own module and requiring it:
//test/lib/homepage.js
var moment = require('moment');
module.exports = {
caseNumber: moment().format('YYYYMMDD-HHmmss-SS'),
getContent: function () { //another example of reuse
return element(by.css('body'));
});
};
//test/homepage.spec.js
var page = require('./lib/homepage');
describe('Homepage', function() {
it('should display correct date', function () {
expect(page.getContent()).toContain(page.caseNumber);
});
});
Related
I have created a custom directive and would like to mock out a variable to make the test working. This is part of the unit test:
it('should pass on initialvalue', function() {
scope.$apply(function() {
scope.initial = 2;
scope.Repairer = null;
});
expect(elementScope.initial).toEqual(2);
});
The directive is calls a service when the initial-variable is set. Both tests are failing because in the directive I have a variable called request that is not properly mocked. The question is how can I mock this out? Or do I need to put the request variable on scope? This is part of the code:
if (scope.Repairer) {
console.log('calling scriptservice');
var request = {
allocationProcess: (scope.$parent.lodgement.searchSettings.automatic.visible) ? 'automatic' : 'direct',
allocationSource: 'internal',
brand: brandScriptTag, // lookup brand scripting name
includeSegment: false,
relationship: scope.repairer.relationshipCode,
ruralSearch: scope.repairer.isRural,
state: scope.$parent.lodgement.claimLocation
};
scriptingService.getScript(request).then(function (scripts) {
scope.scripts = scripts;
});
} else {
scope.scripts = null;
}
plunker ref:http://plnkr.co/edit/juDwpot727jzxzzWeaJl?p=preview
You are accessing an object on the $parent scope, so I'de do somthing like:
$rootScope.lodgement = jasmine.any(Object);
However, your code is problematic since it's asuming a lot about this lodgement...
//it's better to use jasmine.any(Object)
//$rootScope.lodgement = jasmine.any(Object);
var lodgement_mock = {searchSettings:{automatic:{visible:false}}};
$rootScope.lodgement = lodgement_mock;
p.s.
you had another error in your directive - you tried accessing scope.repairer instead of scope.Repairer
check out this:
http://plnkr.co/edit/OFTZff53BXGNLQqRfE8L?p=preview
I'm working on building an extensible automated test suite with Protractor (angularJS/Jasmine framework).
As long as all of my variables and functions and jasmine are in the same file, it runs semi-okay.
But every effort I make to break it into export/require is a nightmare.
Is there a tool that will just find the parts of my test and automatically reformat it and break it into individual files and folders, so that the thing will actually run?
Thanks!
I don´t know a tool for what you want. However if I were you, I would keep working with node's way of sharing files (export/require). Once you understand it, if you keep it clean and tidy, you could grow your app in a "clean" way.
EDIT:
As #MBielski said, Page Objects Model is also helpful when maintaining you test code.
Definition from the Selenium team:
Page Object is a Design Pattern which has become popular in test
automation for enhancing test maintenance and reducing code
duplication. A page object is an object-oriented class that serves as
an interface to a page of your AUT. The tests then use the methods of
this page object class whenever they need to interact with that page
of the UI. The benefit is that if the UI changes for the page, the
tests themselves don’t need to change, only the code within the page
object needs to change. Subsequently all changes to support that new
UI are located in one place.
And now an example without using page objects and then one using it.
Without:
describe('angularjs homepage', function() {
it('should greet the named user', function() {
browser.get('http://www.angularjs.org');
element(by.model('yourName')).sendKeys('Julie');
var greeting = element(by.binding('yourName'));
expect(greeting.getText()).toEqual('Hello Julie!');
});
});
With:
var AngularHomepage = 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();
};
};
describe('angularjs homepage', function() {
it('should greet the named user', function() {
var angularHomepage = new AngularHomepage();
angularHomepage.get();
angularHomepage.setName('Julie');
expect(angularHomepage.getGreeting()).toEqual('Hello Julie!');
});
});
You can also define various test suites. Take a look at this config file:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
capabilities: {
'browserName': 'chrome'
},
// Spec patterns are relative to the location of the spec file. They may
// include glob patterns.
suites: {
homepage: 'tests/e2e/homepage/**/*Spec.js',
search: ['tests/e2e/contact_search/**/*Spec.js',
'tests/e2e/venue_search/**/*Spec.js']
},
jasmineNodeOpts: {
showColors: true, // Use colors in the command line report.
}
};
I have been looking at this document:
understanding-service-types
Because I am new to AngularJS I am having some problems understanding everything in there. I still don't understand the difference between a factory and a service, but I will leave that for another day.
The problem I have now, is that I created a model as a factory and now I think I may have done it wrong.
Here is my model:
commonModule.factory('optionsModel', function () {
var _options = angular.fromJson(sessionStorage.siteOptions);
var _defaults = {
rotateBackground: false,
enableMetro: true
};
if (_options) {
_defaults.rotateBackground = _options.rotateBackground;
_defaults.enableMetro = _options.enableMetro;
}
var _save = function (options) {
console.log(options);
sessionStorage.siteOptions = angular.toJson(options);
}
return {
options: _defaults,
save: _save
};
});
As you can see here, what I am doing is setting the defaults and then I check to see if we have anything in our session, if we do I then overwrite our options with the new settings.
I also have a save function which is used to save the options to the session.
Is this the best way to make this model or should I be doing it another way?
I don't think you should think about a model in the way you're doing it.
For your purpose, you can do it in a more "angular" way :
commonModule.factory('optionsModel', function () {
var factory = {
getOptions: getOptions,
saveOptions: saveOptions
}
// If you need default values, you can assign those here,
// but you can also think about adding a dependency into your factory,
// that would be bound to your default settings.
return factory;
function getOptions(){
return angular.fromJson(sessionStorage.siteOptions);
}
function saveOptions(options){
sessionStorage.siteOptions = angular.toJson(options)
}
});
I was following this question to test the router. My router is really simple:
App.Router = Backbone.Router.extend({
routes:{
"": "index",
"help": "help"
},
help: function() {/* not really needed */ },
index: function(){
// does something
}
});
And this is an apptempted translation of what should be the test using jasmine with sinon:
it('triggers the "index" route', function() {
var router = new App.Router();
Backbone.history.start();
//Not calling navigate it's a problem
router.navigate('help', {
trigger : true, replace: true
});
var index = sinon.spy(router, 'index');
var spyHasPS = sinon.spy(function(
data, title, url) {
expect(url).toEqual('/');
router.index();
});
var spyNoPS = sinon.spy(function(loc, frag) {
expect(frag).toEqual('');
router.index();
});
if (Backbone.history._hasPushState) {
pushStateSpy = sinon.stub(window.history, 'pushState', spyHasPS );
// window.history.pushState();
} else if (Backbone.history._wantsHashChange) {
pushStateSpy = sinon.stub(Backbone.history, '_updateHash', spyNoPS);
//Backbone.history._updateHash(window.location, '');
}
router.navigate('', {
trigger : true, replace: true
});
expect(pushStateSpy.called).toBe(true);
expect(index.called).toBe(true);
});
This test works but I could achieve it because I navigated first on "help". "help" was just something I created to pass the test but the original question didn't do it and was passing. Did I do something wrong? I also run his test but the error I'm getting is:
Expected spy _updateHash to have been called. Error: Expected spy
_updateHash to have been called.
at null.<anonymous> (/src/test/js/spec/wfcRouter.spec.js:65:32) Expected spy index to have been called.
I believe the "problem" is in the navigate function. At a certain point in the navigate: function(fragment, options) we have this control:
fragment = this.getFragment(fragment || '');
if (this.fragment === fragment) return;
So...does it make sense to test the pushState when you just have one route (remember I added "help" just to make this test pass so I don't need it)? If it does make sense, how can I achieve this test?
It seems like what you are testing is Backbone code, but there's no need for you to test that: presumably the Backbone code has been tested plenty by Jeremy Ashkenas (and if you look at the Backbone project on GitHub you will see that he does in fact have a comprehensive test suite). So, rather than re-testing code you didn't write that's already been tested, what you really should be testing is the code you wrote.
If you agree with that principle, then you can simplify your test a great deal, down to just:
it('triggers the "index" route', function() {
var router = new App.Router();
router.index();
expect(thingThatShouldHaveHappenedInIndexRouteDidHappen).toBe(true);
});
I am building an application using the Backbone Boilerplate, and am having some trouble getting underscore template variables to work. I have a resource named Goal. My Goal View's render function looks like this:
render: function(done) {
var view = this;
namespace.fetchTemplate(this.template, function(tmpl) {
view.el.innerHTML = tmpl();
done(view.el);
});
}
I'm calling it inside of another view, like so:
var Goal = namespace.module("goal");
App.View = Backbone.View.extend({
addGoal: function(done) {
var view = new Goal.Views.GoalList({model: Goal.Model});
view.render(function(el) {
$('#goal-list').append(el);
});
}
});
I'm using local storage to save my data, and it's being added just fine. I can see it in the browser, but for some reason, when I load up the app, and try to fetch existing data, i get this error:
ReferenceError: Can't find variable: title
Where title is the only key I'm storing. It is a direct result of calling:
tmpl();
Any thoughts are greatly appreciated.
Your template is looking for a variable title, probably like this <%- title %>. You need to pass it an object like this tmpl({ title: 'Some title' })
Turns out, I wasn't passing in the model when i created the view, which was making it impossible to get the models data. Once I passed in the model correctly, I could then pass the data to tmpl, as correctly stated by #abraham.
render: function(done) {
var
view = this,
data = this.model.toJSON();
clam.fetchTemplate(this.template, function(tmpl) {
view.el.innerHTML = tmpl(data);
done(view.el);
});
},