Mocha Chai regex are equals - regex

I am trying to test the behaviour of a method that produce regex.
Using Mocha/Chai test suite I have the following code :
describe('regexTest',function () {
it('should return a regexp', function () {
var regex = regexTest();
assert.equal(regex, /someregex/);
});
});
But it seems that the code above doesn't work. I tried in the chrome console :
/a/ == /a/
> false
For the moment the only way I found is to compare the toString of the two regex (that should be equals and that I can compare) :
describe('regexTest',function () {
it('should return a regexp', function () {
var regex = regexTest();
assert.equal(regex.toString(), '/someregex/');
});
});
Do you know a better way to do this ? Because I find this not really clean ...

Since regular expression is an object, you need to use deep equals to compare 2 regex objects with each other
expect(/a/).to.be.deep.equal(/a/, 'should match')

Here is how I test if a literal regexp is valid:
var assert = require('assert');
describe('RegExp Test', function() {
it('should return a valid RegExp', function() {
var getSomeRegex = function() {
return /someregex/;
};
var aRegex = getSomeRegex();
assert.equal(aRegex instanceof RegExp, true);
});
it('should return a invalid Regexp', function() {
var getInvalidRegex = function() {
return '/something';
};
var aInvalidRegex = getInvalidRegex();
assert.equal(aInvalidRegex instanceof RegExp, false);
});
});

It's a little late, but for anyone else who stumbles across this on Google way I did, Chai's normal comparison functions work with Regexp objects too...
const re = new RegExp( '^foo.*bar$', 'i' );
re.should.eql( /^foo.*bar$/i );

Related

Unit testing the output of $sce.trustAsHtml in Angular

I am writing a REST app in Angular and I want to write unit tests for it (of course!). I have a controller which gets a list of blog posts from a REST service in json and puts the summaries into the $scope, so I can display them in the view.
At first the blog posts were just displaying as text ie <p>Blog body</p>, rather than rendering as parsed HTML, until I discovered that you can use ng-bind-html in conjunction with the $sce service. This now works fine in terms of displaying the blog posts correctly.
The problem arises when unit testing. I am trying to mock a json response with some HTML and then test that my controller is correctly dealing with the HTML. Here is my code:
Controller
.controller( 'HomeCtrl', function HomeController( $scope, $http, $sce ) {
$scope.posts = {};
$http.get('../drupal/node.json').success(function (data) {
var posts;
posts = data.list;
for(var i = 0; i < posts.length; i ++) {
posts[i].previewText = $sce.trustAsHtml(posts[i].body.summary);
posts[i].created = posts[i].created + '000'; // add milliseconds so it can be properly formatted
}
$scope.posts = posts;
});
})
unit test
describe('HomeCtrl', function() {
var $httpBackend, $rootScope, $sce, createController;
beforeEach(inject(function ($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// Get hold of a scope (i.e. the root scope)
$rootScope = $injector.get('$rootScope');
// The $controller service is used to create instances of controllers
var $controller = $injector.get('$controller');
$sce = $injector.get('$sce');
createController = function() {
return $controller('HomeCtrl', {
'$scope': $rootScope
});
};
}));
it('should get a list of blog posts', function() {
var rawResponse = {
"list": [
{
"body": {
"value": "\u003Cp\u003EPost body.\u003C\/p\u003E\n",
"summary": "\u003Cp\u003ESummary.\u003C\/p\u003E\n"
},
"created": "1388415860"
}
]};
var processedResponse = [{
"body": {
"value": "\u003Cp\u003EPost body.\u003C\/p\u003E\n",
"summary": "\u003Cp\u003ESummary.\u003C\/p\u003E\n"
},
"created": "1388415860000",
previewText: $sce.trustAsHtml("\u003Cp\u003ESummary.\u003C\/p\u003E\n")
}];
$httpBackend.when('GET', '../drupal/node.json').respond(rawResponse);
$httpBackend.expectGET("../drupal/node.json").respond(rawResponse);
var homeCtrl = createController();
expect(homeCtrl).toBeTruthy();
$httpBackend.flush();
expect($rootScope.posts).toEqual(processedResponse);
});
});
When I run the above through the Karma test runner, I get the following response:
Chrome 31.0.1650 (Windows) home section HomeCtrl should get a list of blog posts FAILED
Expected [ { body : { value : '<p>Post body.</p>
', summary : '<p>Summary.</p>
' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } } ] to equal [ { body
: { value : '<p>Post body.</p>
', summary : '<p>Summary.</p>
' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } } ].
I suspect the problem is due to the fact that $sce.trustAsHtml returns an object containing a function, rather than a string.
My question is, firstly, am I approaching this problem in the correct way?
Secondly, if so, how should I go about testing the output of $sce.trustAsHtml?
Since the answer given by michael-bromley didn't work for me I want to point out another solution. In my case I was using a filter that wraps each occurrence of a string in another string with a span that has a class of 'highlight'. In other words, I want words to be highlighted. Here is the code:
angular.module('myModule').filter('highlight', function ($sce) {
return function (input, str) {
return $sce.trustAsHtml((input || '').replace(new RegExp(str, 'gi'), '<span class=\"highlighted\">$&</span>'));
};
});
I use the $sce service to trust the resulting value as HTML. To test this I need to use the $$unwrapTrustedValue function on the resulting value to get my test working:
it('01: should add a span with class \'highlight\' around each mathing string.', inject(function ($filter) {
// Execute
var result = $filter('highlight')('this str contains a str that will be a highlighted str.', 'str');
// Test
expect(result.$$unwrapTrustedValue()).toEqual('this <span class="highlighted">str</span> contains a <span class="highlighted">str</span> that will be a highlighted <span class="highlighted">str</span>.');
}));
UPDATE:
As #gugol kindly pointed out it is preferred not to use Angular internal methods like $$unwrapTrustedValue. A better approach is to use the public getTrustedHtml method on the $sce service. Like so:
it('01: should add a span with class \'highlight\' around each mathing string.', inject(function ($sce, $filter) {
// Execute
var result = $filter('highlight')('this str contains a str that will be a highlighted str.', 'str');
// Test
expect($sce.getTrustedHtml(result)).toEqual('this <span class="highlighted">str</span> contains a <span class="highlighted">str</span> that will be a highlighted <span class="highlighted">str</span>.');
}));
You have to disable $sce using its provider before each test.
When $sce is disabled all $sce.trust* methods just return original value instead of a wrapper function.
beforeEach(module(function ($sceProvider) {
$sceProvider.enabled(false);
}));
it('shall pass', inject(function($sce){
expect($sce.trustAsHtml('<span>text</span>')).toBe('<span>text</span>');
}));
In your particular example just do this:
describe('HomeCtrl', function() {
var $httpBackend, $rootScope, $sce, createController;
beforeEach(module(function ($sceProvider) {
$sceProvider.enabled(false);
}));
// rest of the file
});
I discovered that you can use $sce.getTrusted which will return the value originally passed to $sce.trustAsHtml, in this case a string containing HTML, which you can then test for equality in the usual way.
So my test now looks like this:
it('should create a previewText property using $sce.trustAsHtml', function() {
// confirms that it is an object, as should be the case when
// it has been through $sce.trustAsHtml
expect(typeof result.previewText === 'object').toEqual(true);
expect($sce.getTrusted($sce.HTML, result.previewText))
.toEqual('<p>Original HTML content string</p>');
});
Another option is to use the getTrustedHtml() function to get the html string value from $$unwrapTrustedValue.
vm.user.bio = $sce.getTrustedHtml(vm.user.bio);

how to call variables scoped in describe constructor in jasmine

I am using jasmine runner to test angular code.
describe('des1', function() {
var des1Var = function(){};
beforeEach() {
//....
}
describe('test1', function() {
var scope4Compile = $rootScope.$new();
var des2Var = des1Var(scope4Compile); // returns undefined.
beforeEach(function() {
des2Var = des1Var(scope4Compile); // returns des1Var() fine;
})
it('should do ', function(){
//should do...
})
it('should also do', function(){
//should also do...
})
})
})
I need to instantiate something once before the it statements, if run multiple times result is pretty bad. How can I get it done properly?
I believe it you call it once in the first beforeEach it will be run one time for each describe that is below it.
In the code below, des2Var will be set once for the whole test1 describe.
describe('des1', function() {
var des1Var = function () { };
beforeEach(function () {
var des2Var = des1Var();
});
describe('test1', function() {
it('should do ', function(){
//should do...
});
it('should also do', function(){
//should also do...
});
});
});

Testing asynchrone function gives Unexpected request

The unittest:
"use strict";
var usersJSON = {};
describe("mainT", function () {
var ctrl, scope, httpBackend, locationMock,
beforeEach(module("testK"));
beforeEach(inject(function ($controller, $rootScope, $httpBackend, $location, $injector) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
locationMock = $location;
var lUrl = "../solr/users/select?indent=true&wt=json",
lRequestHandler = httpBackend.expect("GET", lUrl);
lRequestHandler.respond(200, usersJSON);
ctrl = $controller("mainT.controller.users", { $scope: scope, $location: locationMock});
httpBackend.flush();
expect(scope.users).toBeDefined();
}));
afterEach(function () {
httpBackend.verifyNoOutstandingRequest();
httpBackend.verifyNoOutstandingExpectation();
});
describe("method test", function () {
it('should test', function () {
expect(true).toBeFalsy();
});
});
});
controller I'm testing (working):
Asynchrone function in init who's giving me trouble (uses ../solr/users/select?indent=true&wt=json):
$scope.search = function () {
var lStart = 0,
lLimit = privates.page * privates.limit;
Search.get({
collection: "users",
start: lStart,
rows: lLimit)
}, function(records){
$scope.users= records.response.docs;
});
};
What I think happens:
1. inform backend what request he will receive
2. inform backend to response on that request with empty JSON
3. create a controller (Search.get get's executed)
4. inform backend to receive all requests and answer them (flush)
Yet I always get the following error:
Error: Unexpected request: GET : ../solr/users/select?indent=true&wt=json
Am I not handling the asynchrone search function well? how should this be done?
That's not really a "unit" test, it's more of a behavioral test.
This should really be a few tests:
Test your service Search.get to make sure it's calling the proper URL and returning the result.
Test your controller method to make sure it's calling Search.get
Test your controller method to make sure it's putting the result in the proper spot.
The code you've posted is a little incomplete, but here are two unit tests that should cover you:
This is something I've blogged about extensively, and the entries go into more detail:
Unit Testing Angular Controllers
Unit Testing Angular Services
Here's an example of what I'm talking about:
describe('Search', function () {
var Search,
$httpBackend;
beforeEach(function () {
module('myModule');
inject(function (_Search_, _$httpBackend_) {
Search = _Search_;
$httpBackend = _$httpBackend_;
});
});
describe('get()', function () {
var mockResult;
it('should call the proper url and return a promise with the data.', function () {
mockResult = { foo: 'bar' };
$httpBackend.expectGET('http://sample.com/url/here').respond(mockResult);
var resultOut,
handler = jasmine.createSpy('result handler');
Search.get({ arg1: 'wee' }).then(handler);
$httpBackend.flush();
expect(handler).toHaveBeenCalledWith(mockResult);
$httpBackend.verifyNoOutstandingRequest();
$httpBackend.verifyNoOutstandingExpectation();
});
});
});
describe('myCtrl', function () {
var myCtrl,
$scope,
Search;
beforeEach(function () {
module('myModule');
inject(function ($rootScope, $controller, _Search_) {
$scope = $rootScope.$new();
Search = _Search;
myCtrl = $controller('MyCtrl', {
$scope: scope
});
});
});
describe('$scope.foo()', function () {
var mockResult = { foo: 'bar' };
beforeEach(function () {
//set up a spy.
spyOn(Search, 'get').andReturn({
then: function (fn) {
// this is going to execute your handler and do whatever
// you've programmed it to do.. like $scope.results = data; or
// something.
fn(mockResult);
}
});
$scope.foo();
});
it('should call Search.get().', function () {
expect(Search.get).toHaveBeenCalled();
});
it('should set $scope.results with the results returned from Search.get', function () {
expect(Search.results).toBe(mockResult);
});
});
});
In a BeforeEach you should use httpBackend.when instead of httpBackend.expect. I don't think you should have an assertion (expect) in your BeforeEach, so that should be moved to a separate it() block. I also don't see where lRequestHandler is defined. The 200 status is sent by default so that is not needed. Your httpBackend line should look like this:
httpBackend.when("GET", "/solr/users/select?indent=true&wt=json").respond({});
Your test should then be:
describe("method test", function () {
it('scope.user should be defined: ', function () {
expect(scope.user).toEqual({});
});
});
Your lUrl in the unit test, shouldn't be a relative path, i.e., instead of "../solr/users/select?indent=true&wt=json" it should be an absolute "/solr/users/select?indent=true&wt=json". So if your application is running at "http://localhost/a/b/index.html", lUrl should be "/a/solr/...".
Note that you can also use regular expressions in $httpBackend.expectGET(), that could be helpful here in case you are not entirely sure how the absolute path will look like later on.

How to write unit test for AngularJS model

I've got a basic model that I am trying to write a simple unit test suite for, and I'm clearly missing something...
The code for the model looks like this:
angular.module('AboutModel', [])
.factory(
'AboutModel',
[
function () {
var paragraphs = [];
var AboutModel = {
setParagraphs: function (newParagraphs) {
paragraphs = newParagraphs;
},
getParagraphs: function () {
return paragraphs;
}
};
return AboutModel;
}
]
);
The requirement is simple: provide a getter and a setter method for the private array called paragraphs.
And here is as far as I have got with the test suite code:
describe('Testing AboutModel:', function () {
describe('paragraphs setter', function () {
beforeEach(module('AboutModel'));
it('sets correct value', inject(function (model) {
// STUCK HERE
// don't know how to access the model, or the setParagraphs() method
}));
});
describe('paragraphs getter', function () {
// not implemented yet
});
});
I've been doing quite a bit of google research on the web, but so far no joy.
The solution must be simple; please help!
And it might even be the case that there's a better way of implementing the Model... open to suggestions to make it better.
For anyone interested, the full source code is here:
https://github.com/mcalthrop/profiles/tree/imp/angular
thanks in advance
Matt
You need to run a beforeEach in your test to inject the model instance and then assign it to a variable which you can then re-use through out your tests.
var AboutModel;
beforeEach(inject(function (_AboutModel_) {
AboutModel = _AboutModel_;
}));
You can then access your getter like so:
AboutModel.getParagraphs();
I have tweaked your original model slightly as I feel it reads a little better (my preference):
'use strict';
angular.module('anExampleApp')
.factory('AboutModel', function () {
var _paragraphs;
// Public API here
return {
setParagraphs: function (newParagraphs) {
_paragraphs = newParagraphs;
},
getParagraphs: function () {
return _paragraphs;
}
};
});
And then for testing I would use a combination of the standard Jasmine tests and spies:
'use strict';
describe('Service: AboutModel', function () {
beforeEach(module('anExampleApp'));
var AboutModel, paragraphs = ['foo', 'bar'];
beforeEach(inject(function (_AboutModel_) {
AboutModel = _AboutModel_;
}));
it('should set new paragraphs array', function () {
AboutModel.setParagraphs([]);
expect(AboutModel.getParagraphs()).toBeDefined();
});
it('should call setter for paragraphs', function () {
spyOn(AboutModel, 'setParagraphs');
AboutModel.setParagraphs(paragraphs);
expect(AboutModel.setParagraphs).toHaveBeenCalledWith(paragraphs);
});
it('should get 2 new paragraphs', function () {
AboutModel.setParagraphs(['foo', 'bar']);
expect(AboutModel.getParagraphs().length).toEqual(2);
});
});

How to properly unit test jQuery's .ajax() promises using Jasmine and/or Sinon?

I've got a fairly straightforward function which returns a jQuery .ajax() promise as such:
CLAW.controls.validateLocation = function(val, $inputEl) {
return $.ajax({
url: locationServiceUrl + 'ValidateLocation/',
data: {
'locationName': val
},
beforeSend: function() {
$inputEl.addClass('busy');
}
}).done(function(result) {
// some success clauses
}).fail(function(result) {
// some failure clauses
}).always(function() {
// some always clauses
});
}
For the most part, this new promises interface works like a dream, and eliminating callback pyramids when using jQuery's .ajax() is great. However, I cannot for the life of me figure out how to properly test these promises using Jasmine and/or Sinon:
All of Sinon's documentation assumes you're using old-school
callbacks; I don't see a single example of how to use it with
promises/deferreds
When attempting to use a Jasmine or Sinon spy to spy on $.ajax, the
spy is effectively overwriting the promise, so its done, fail,
and always clauses no longer exist on the ajax function, so the promise never resolves and tosses an error instead
I'd really just love an example or two of how to test these new jQuery .ajax() promises with the aforementioned testing libs. I've scoured the 'net fairly intensely and haven't really dredged up anything on doing so. The one resource I did find mentioned using Jasmine.ajax, but I'd like to avoid that if possible, seeing as Sinon provides most of the same capabilities out-of-the-box.
It is not that complex actually. It suffices to return a promise and resolve it according to your case.
For example:
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.resolve(data_you_expect);
return d.promise();
});
for a success, or
spyOn($, 'ajax').andCallFake(function (req) {
var d = $.Deferred();
d.reject(fail_result);
return d.promise();
});
for a failure.
For Jasmine 2.0 the syntax has changed slightly:
spyOn($, 'ajax').and.callFake(function (req) {});
the method .andCallFake() does not exist in Jasmine 2.0
something along these lines / with sinon and jQuery deferreds
ajaxStub = sinon.stub($, "ajax");
function okResponse() {
var d = $.Deferred();
d.resolve( { username: "testuser", userid: "userid", success: true } );
return d.promise();
};
function errorResponse() {
var d = $.Deferred();
d.reject({},{},"could not complete");
return d.promise();
};
ajaxStub.returns(okResponse());
ajaxStub.returns(errorResponse());
Here's a simpler approach with just javascript.
quoteSnapshots: function (symbol, streamId) {
var FakeDeferred = function () {
this.error = function (fn) {
if (symbol.toLowerCase() === 'bad-symbol') {
fn({Error: 'test'});
}
return this;
};
this.data = function (fn) {
if (symbol.toLowerCase() !== 'bad-symbol') {
fn({});
}
return this;
};
};
return new FakeDeferred();
}
The if statements inside of each callback are what I use in my test to drive a success or error execution.
The solution given by #ggozad won't work if you use things like .complete().
But, hooray, jasmine made a plugin to do exactly this: http://jasmine.github.io/2.0/ajax.html
beforeEach(function() {
jasmine.Ajax.install();
});
afterEach(function() {
jasmine.Ajax.uninstall();
});
//in your tests
expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');