Setting cookies for internjs functional tests - javascript

I'm trying to set a cookie for an intern functional test, but the cookie data doesn't seem to be available on the page. Here's the setup:
registerSuite(function() {
'test': function() {
return this.remote
.get(require.toUrl("index.html")
.setFindTimeout(5000)
.setCookie({name: "foo", value: "bar"})
.then(function() {
//... test here ...
});
}
});
When accessing document.cookie inside index.html, there is no data. Any tips on what I am doing wrong?
Update:
I haven't solved the problem, but figured out that you need call setCookie() before get(). The way I'm hacking around this is to call get() on a noop URL, and then calling setCookie()
return this.remote
.get('/')
.setCookie({name: "foo", value: "bar"})
.get(require.toUrl("index.html")
.setFindTimeout(5000)
.setCookie({name: "foo", value: "bar"})
.then(function() {
//... test here ...
});

It would seem you did not include in your sample code any setup, teardown/after, beforeEach or afterEach. I would recommend making sure the functionality works at all before evaluating the cookie you expect it to create.
I am not terribly familiar with Intern.JS but I believe from what I read the tests are only a test and once completed they remove information from the test so the next test can be performed. So, maybe you are missing when the cookie is in existence and when the test is completed it gets destroyed.

Related

Deps autorun in Meteor JS

Decided to test out Meteor JS today to see if I would be interested in building my next project with it and decided to start out with the Deps library.
To get something up extremely quick to test this feature out, I am using the 500px API to simulate changes. After reading through the docs quickly, I thought I would have a working example of it on my local box.
The function seems to only autorun once which is not how it is suppose to be working based on my initial understanding of this feature in Meteor.
Any advice would be greatly appreciated. Thanks in advance.
if (Meteor.isClient) {
var Api500px = {
dep: new Deps.Dependency,
get: function () {
this.dep.depend();
return Session.get('photos');
},
set: function (res) {
Session.set('photos', res.data.photos);
this.dep.changed();
}
};
Deps.autorun(function () {
Api500px.get();
Meteor.call('fetchPhotos', function (err, res) {
if (!err) Api500px.set(res);
else console.log(err);
});
});
Template.photos.photos = function () {
return Api500px.get();
};
}
if (Meteor.isServer) {
Meteor.methods({
fetchPhotos: function () {
var url = 'https://api.500px.com/v1/photos';
return HTTP.call('GET', url, {
params: {
consumer_key: 'my_consumer_key_here',
feature: 'fresh_today',
image_size: 2,
rpp: 24
}
});
}
});
}
Welcome to Meteor! A couple of things to point out before the actual answer...
Session variables have reactivity built in, so you don't need to use the Deps package to add Deps.Dependency properties when you're using them. This isn't to suggest you shouldn't roll your own reactive objects like this, but if you do so then its get and set functions should return and update a normal javascript property of the object (like value, for example), rather than a Session variable, with the reactivity being provided by the depend and changed methods of the dep property. The alternative would be to just use the Session variables directly and not bother with the Api500px object at all.
It's not clear to me what you're trying to achieve reactively here - apologies if it should be. Are you intending to repeatedly run fetchPhotos in an infinite loop, such that every time a result is returned the function gets called again? If so, it's really not the best way to do things - it would be much better to subscribe to a server publication (using Meteor.subscribe and Meteor.publish), get this publication function to run the API call with whatever the required regularity, and then publish the results to the client. That would dramatically reduce client-server communication with the same net result.
Having said all that, why would it only be running once? The two possible explanations that spring to mind would be that an error is being returned (and thus Api500px.set is never called), or the fact that a Session.set call doesn't actually fire a dependency changed event if the new value is the same as the existing value. However, in the latter case I would still expect your function to run repeatedly as you have your own depend and changed structure surrounding the Session variable, which does not implement that self-limiting logic, so having Api500px.get in the autorun should mean that it reruns when Api500px.set returns even if the Session.set inside it isn't actually doing anything. If it's not the former diagnosis then I'd just log everything in sight and the answer should present itself.

Spyon provider during config phase in angular.js application

I am writing unit tests for an Angular.js application (with karma and jasmine), and I want to test a certain behavior in the CONFIG phase of a module. I would like to confirm that a certain function of a PROVIDER is being called. I thought I could do this with a spy on the provider's method, but gaining access to the provider before the "expect" has proven rather tricky.
Here is some example code:
Module Code (being tested)
var myApp = angular.module('myApp', ['restangular']);
myApp.config(['RestangularProvider', function (RestangularProvider) {
RestangularProvider.setBaseUrl('http://someurl:someport/');
}]);
I've tried various solutions to get a reference to the RestangularProvider and apply a spy to it, and all failed. The closest I was able to get was the code below:
Unit Test Code
describe("Test if setBaseUrl was called", function () {
var RestangularProvider;
beforeEach(module('myApp', function(_RestangularProvider_) {
RestangularProvider = _RestangularProvider_;
spyOn(RestangularProvider, "setBaseUrl").and.callThrough();
}));
it("should call setBaseUrl.", function() {
expect(RestangularProvider.setBaseUrl).toHaveBeenCalled();
});
});
I do actually get the reference to the RestangularProvider, but the "config" function of the module gets called before that, so I think the spy doesn't get set-up.
I did find a post where the author solved a similar situation with a "work around" by testing the configured "service" instead of testing the actual call to the provider's method. In the example above, I would test the Restangular.configuration.baseUrl in my expect instead of testing the actual call to the provider's setBaseUrl method, but this seemed like it would not be adequate in certain situations.
I am rather new to Angular.js so this may simply be a case of being totally clueless as to the whole "testing config phase", so if that's the case, please feel free to set me straight :]
Any suggestions, critiques or pointers?
I finally solved the problem by separating out the module, whose provider I wanted to spy on, into a diferent "beforeEach" block. The altered code is below, but I still would appreciate any comments as to the whole idea of whether or not this is actually an "adequate test".
describe("Test if setBaseUrl was called", function () {
var RestangularProvider;
//Setup the spy.
beforeEach(function () {
module("restangular", function(_RestangularProvider_) {
RestangularProvider = _RestangularProvider_;
spyOn(_RestangularProvider_, 'setBaseUrl').and.callThrough();
});
});
beforeEach(module('myApp'));
it("should call setBaseUrl.", function() {
expect(RestangularProvider.setBaseUrl).toHaveBeenCalled();
});
});
As described by OP above, you do need to get the provider before calling the module you want to test.
However, there's no need to separate it in two beforeEach blocks. You also must call inject() function (even if you have nothing to inject) at the end of the beforeEach block.
describe('Test if setBaseUrl was called', function () {
var RestangularProvider;
//Setup the spy.
beforeEach(function () {
module('restangular', function(_RestangularProvider_) {
RestangularProvider = _RestangularProvider_;
spyOn(_RestangularProvider_, 'setBaseUrl').and.callThrough();
});
module('myApp');
inject();
});
it('should call setBaseUrl.', function() {
expect(RestangularProvider.setBaseUrl).toHaveBeenCalled();
});
});
Source: http://java.dzone.com/articles/unit-testing-config-and-run

Why are my tests failing and console.log() statements within a lodash method not logging?

I have some failing tests that are breaking at various lodash methods but work fine in the browser. While trying to debug I threw in some console.log()s within the callback argument to see what's going on, but they are not showing up in tests. The same code run in the browser both works fine and writes to the console. I suspect the breaking functionality is related to the missing log statements.
This is an Angular app in which I'm supplying lodash as a service.
app
app.value('_', window._);
app.service('myService', function(_) {
return {
filterNulls: function(obj) {
// This logs correctly everywhere
console.log(obj);
return _.omit(obj, function(val, key) {
// This logs in browsers but not in the Jasmine/Karma environment
console.log('test');
return val === null;
});
}
};
});
tests
describe('myService', function() {
beforeEach(function() {
module(function($provide) {
$provide.value('_', window._);
});
});
it('should strip nulls', inject(function(myService) {
// FAILS because null value is not removed
expect(myService.filterNulls({
key: 'key1',
someProp: 'bar',
someOtherProp: null
}))
.toEqual({
key: 'key1',
someProp: 'bar'
});
});
});
I'm not sure of why your logs aren't showing when Karma runs - they do for me when I test your code. There may be another problem which is not obvious to you or me.
I can say that your usage of _.omit is incorrect. From the docs:
The callback is bound to thisArg and invoked with three arguments;
(value, key, object).
Meanwhile, your callback parameters look like this:
function(key, val) { .. }
This minor adjustment makes your test pass for me:
function(val) { .. }
It turns out the problem was an incorrect lodash reference. The karma.config file was referencing a different version (lodash.underscore.js) than the application (lodash.compat.js). A simple problem of collaborative development inconsistencies.

Is there a way to `goog.provide` something without using the global object?

Using the global object for this has been problematic for me. Here is a simple example that illustrates my problem:
In a.js:
goog.provide('app.a');
goog.require('app.b');
app.a = function () {
return [
app.b('Hey, there!'),
app.c('yo')
];
};
Note in the above file, I am using app.c without explicitly requiring it.
In b.js:
goog.provide('app.b');
goog.require('app.c');
app.b = function (msg) {
return app.c('b ' + msg);
};
In c.js:
goog.provide('app.c');
app.c = function (msg) {
return { msg: msg };
};
I can run this through closurebuilder and it will run just fine. It will also run without error in the browser. But I don't like how app.c is usable without being explicitly required.
The best solution I can think of is if each file could somehow use its own copy of the app global variable that is built up from the goog.require calls. This would result in runtime errors when you try to use something that wasn't required. Not sure if this is possible.
Is there a way to do what I described, or is there some alternative?
There's no reason not to put a require for app.c in app.a, and that is a best practice but yeah it won't catch it if you don't because of the way requirements are harvested by the compiler. It would throw an error if you removed the app.b requirement, just one of the many, many, many quirks of closure land.

How to mock $window.location.replace in AngularJS unit test?

I've got the following service:
angular.module("services")
.factory("whatever", function($window) {
return {
redirect: function() {
$window.location.replace("http://www.whatever.com");
}
};
});
How to mock $window object in unit test to prevent reloading the page when running tests?
I tried using
spyOn($window.location, 'replace').andReturn(true);
, but it didn't work (still got "Some of your tests did a full page reload!" error) and
$provide.value('$window', {location: {replace: jasmine.createSpy()}})
, but I was getting an error (Error: [ng:areq] Argument 'fn' is not a function, got Object) with stack trace pointing only to angular own source, so it wasn't very helpful...
In Chrome (didn't test inother browsers), location.replace is readonly so spyOn wasn't able to replace it.
$provide.value should work. Something must be wrong somewhere in your code.
Here is a working unit test
describe('whatever', function() {
var $window, whatever;
beforeEach(module('services'));
beforeEach(function() {
$window = {location: { replace: jasmine.createSpy()} };
module(function($provide) {
$provide.value('$window', $window);
});
inject(function($injector) {
whatever = $injector.get('whatever');
});
});
it('replace redirects to http://www.whatever.com', function() {
whatever.redirect();
expect($window.location.replace).toHaveBeenCalledWith('http://www.whatever.com');
});
});
I'm going with an easier but perhaps less elegant solution. I'm writing a wrapper for $window.location, which I can then mock. Relating that to your code, I'd be mocking the whatever.redirect function, rather than mocking $window (I'm assuming here that your real function is more complex).
So I'd end up with:
angular.module("services")
.factory("whatever", function($window) {
return {
do_stuff_that_redirects: function() {
lots of code;
this.redirect("http://www.whatever.com");
maybe_more_code_maybe_not;
},
redirect: function(url) {
$window.location.replace(url);
}
};
});
I can then directly mock the redirect method, and just trust that since it's only one line of code it can't really go wrong.
spyOn(whatever, 'redirect').andCallFake(function(){});
expect(whatever.redirect).toHaveBeenCalledWith('http:/my.expected/url');
This is sufficient for my purposes, and lets me validate the url called.
I'll offer another approach that might work for you. I faced the same problem while unit testing a controller 'action' that ultimately redirects the user (full-page-load, but to a different page in the larger website/application). To give some context, the controller fires off an AJAX request, and if the response is OK, it will redirect the user to a different page via $window.location.replace():
$http.post('save', data)
.success(function(responseData, status, headers, config) {
if(responseData.redirect) {
$window.location.replace(responseData.redirect);
}
})
.error(function(responseData, status, headers, config) {
console.error("ERROR while trying to create the Event!!");
});
The test for this controller function caused the same "Some of your tests did a full page reload!" error. So I added the following to the beforeEach() function for the controller spec, to mock out the $window service:
mockWindow = { location: { replace: function(url) { console.log('redirecting to: ' + url); } } };
eventCtrl = $controller('EventCtrl', { $scope: scope, $window: mockWindow });
Of course, this solution prevents me from (cleanly) verifying that the replace function was called with an expected argument, but I don't really care about that right now.... Hope that helps.
I think what you want is to use the $location service, rather then calling $window.location. There is also a whole page explaining this feature here: http://docs.angularjs.org/guide/dev_guide.services.$location.
Using this, it should be fairly simple to use a stubbed version of the $location service in you tests.
$location.path('/someNewPath');
$location.replace();
// or you can chain these as: $location.path('/someNewPath').replace();

Categories

Resources