What does "function (assert)" do? - qunit

I've just started becoming acquainted with qunit and I'm trying to get through the official introduction.
There are quite a lot of questions arising and I can't find anything on their documentation about qunit or elsewhere on the web.
What does "function (assert)" do? Assert is a category in qunit for several assertion methods, yet it isn't a method by itself. So if I put "assert" into the parameter of a function, what happens? Are all assertion methods associated with "assert" executed in the test?
https://qunitjs.com/intro/
Here's one piece of code where this syntax is used
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Refactored date examples</title>
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.5.0.css">
<script src="https://code.jquery.com/qunit/qunit-2.5.0.js"></script>
<script src="prettydate.js"></script>
<script>
QUnit.test("prettydate basics", function( assert ) {
var now = "2008/01/28 22:25:00";
assert.equal(prettyDate(now, "2008/01/28 22:24:30"), "just now");
assert.equal(prettyDate(now, "2008/01/28 22:23:30"), "1 minute ago");
assert.equal(prettyDate(now, "2008/01/28 21:23:30"), "1 hour ago");
assert.equal(prettyDate(now, "2008/01/27 22:23:30"), "Yesterday");
assert.equal(prettyDate(now, "2008/01/26 22:23:30"), "2 days ago");
assert.equal(prettyDate(now, "2007/01/26 22:23:30"), undefined);
});
</script>
</head>
<body>
<div id="qunit"></div>
</body>
</html>

The full line is:
QUnit.test("prettydate basics", function( assert ) {
This calls the function QUnit.test, and you're passing it a callback. That callback takes one parameter. QUnit.test will pass an object as the first argument to your callback, which becomes your assert parameter. That object has various methods for asserting things.
It's basically injecting the assertion object into your code so you can use it to make assertions.
Roughly QUnit.test is implemented like this:
QUnit.test = function (name, callback) {
const assert = {
equal: function () { ... },
...
};
callback(assert);
};

Related

Jasmine Test Cases for click and toggle events

Struggling on writing the testcases on click,toggle,slideUp,fade events.
How do I write jasmine test cases to check if div is clicked or not and the slideUp and down and toggle events. Is there a provision in jasmine to test them.
Have listed my code having click test case for reference.
SpecRunner.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v2.3.4</title>
<link rel="shortcut icon" type="image/png" href="lib_jasmine/jasmine- 2.3.4/jasmine_favicon.png">
<link rel="stylesheet" href="lib_jasmine/jasmine-2.3.4/jasmine.css">
<script src="scripts/jquery.js"></script>
<script src="lib_jasmine/jasmine-2.3.4/jasmine.js"></script>
<script src="lib_jasmine/jasmine-2.3.4/jasmine-html.js"></script>
<script src="lib_jasmine/jasmine-2.3.4/boot.js"></script>
<script src="lib_jasmine/jasmine-2.3.4/jasmine-jquery.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="js/eigMain.js"></script>
<script type="text/javascript" src="js/sinon.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="js/specEig.js"></script>
</head>
<body>
</body>
</html>
js file for reference
$('#screenPane').click(function(e){
$('#Panel,.FixedHeader').toggleClass('fullscreen');
$('#eIcon').toggle();
$('#cIcon').toggle();
$(".Col").toggle();
$('html, body').animate({scrollTop: $('#total-results').offset().top}, 800);
$('#nav_up').fadeIn('slow');
$('#nav_down').hide();
});
Spec.js file having click event test case on it. It gives me ERROR : Expected event [object Object] to have been triggered on [object Object]. Also, toggle test case fails to execute.
it ("should invoke the screenPane click event.", function() {
spyOnEvent($('#screenPane'), 'click');
$('#screenPane').click();
expect('click').toHaveBeenTriggeredOn($('#screenPane'));
});
Please help
While most tags accept or react to a click event, detecting it may prove difficult on the various platforms and browsers. You would probably be better checking to see if the CSS classes that toggle() deals with have been swapped in response to the click. For checking anything that is going to get moved around, simply check the starting X/Y coordinates and then compare them to the ones when the animation is finished and just check to see if they are different (so as to not create a brittle situation with strictly defined values.)
//Checking coordinates
it ("should invoke the screenPane click event.", function() {
var coords = $('screenPane').offset();
$('#screenPane').click();
var newCoords = $('screenPane').offset();
expect(newCoords).not.toEqual(coords);
});
//Checking classes
it ("should invoke the screenPane click event.", function() {
var classes = $('screenPane').val('class');
$('#screenPane').click();
var newClasses = $('screenPane').val('class');
expect(classes).not.toEqual(newClasses);
});

Thymeleaf th:inline="javascript" issue

I don't know how to solve the following: I'd like to let my Model generate real javascript dynamically based on some model logic.
This final piece of javascript code then should be added inside the $(document).ready { } part of my html page.
The thing is: If I use inline="javascript", the code gets quoted as my getter is a String (that is how it is mentioned in the Thymeleaf doc but it's not what I need ;-)
If I use inline="text" in is not quoted but all quotes are escaped instead ;-) - also nice but unusable 8)
If I try inline="none" nothing happens.
Here are the examples
My model getter created the following Javascript code.
PageHelper class
public String documentReady() {
// do some database operations to get the numbers 8,5,3,2
return "PhotoGallery.load(8,5,3,2).loadTheme(name='basic')";
}
So if I now try inline="javascript"
<script th:inline="javascript">
/*<![CDATA[*/
jQuery().ready(function(){
/*[[${pageHelper.documentReady}]]*/
});
/*]]>*/
</script>
it will be rendered to
<script>
/*<![CDATA[*/
jQuery().ready(function(){
'PhotoGallery.load(8,5,3,2).loadTheme(name=\'basic\')'
});
/*]]>*/
</script>
Which doesn't help as it is a String literal, nothing more (this is how Thymeleaf deals with it).
So if I try inline="text" instead
<script>
/*<![CDATA[*/
jQuery().ready(function(){
PhotoGallery.load(8,5,3,2).loadTheme(name='basic')
});
/*]]>*/
</script>
Which escapes the quotes.
inline="none" I do not really understand, as it does nothing
<script>
/*<![CDATA[*/
jQuery().ready(function(){
[[${pageHelper.documentReady}]]
});
/*]]>*/
</script>
To be honest I have no idea how to solve this issue and hopefully anybody out there knows how to deal with this.
Many thanks in advance
Cheers
John
I would change the approach.
Thymeleaf easily allows you to add model variables in your templates to be used in Javascript. In my implementations, I usually put those variables somewhere before the closing header tag; to ensure they're on the page once the JS loads.
I let the template decide what exactly to load, of course. If you're displaying a gallery, then render it as you would and use data attributes to define the gallery that relates to some JS code. Then write yourself a nice jQuery plugin to handle your gallery.
A relatively basic example:
Default Layout Decorator: layout/default.html
<!doctype html>
<html xmlns:layout="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org">
<head>
<title>My Example App</title>
<object th:remove="tag" th:include="fragments/scripts :: header" />
</head>
<body>
<div layout:fragment="content"></div>
<div th:remove="tag" th:replace="fragments/scripts :: footer"></div>
<div th:remove="tag" layout:fragment="footer-scripts"></div>
</body>
</html>
The thing to notice here is the inclusion of the generic footer scripts and then a layout:fragment div defined. This layout div is what we're going to use to include our jQuery plugin needed for the gallery.
File with general scripts: fragments/scripts.html
<div th:fragment="header" xmlns:th="http://www.thymeleaf.org">
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
var MY_APP = {
contextPath: /*[[#{/}]]*/,
defaultTheme: /*[[${theme == null} ? null : ${theme}]]*/,
gallery: {
theme: /*[[${gallery == null} ? null : ${gallery.theme}]]*/,
images: /*[[${gallery == null} ? null : ${gallery.images}]]*/,
names: /*[[${gallery == null} ? null : ${gallery.names}]]*/
}
};
/*]]>*/
</script>
</div>
<div th:fragment="footer" xmlns:th="http://www.thymeleaf.org">
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/my_app.js"></script>
</div>
In the scripts file, there are 2 fragments, which are included from the decorator. In the header fragment, a helpful context path is included for the JS layer, as well as a defaultTheme just for the hell of it. A gallery object is then defined and assigned from our model. The footer fragment loads the jQuery library and a main site JS file, again for purposes of this example.
A page with a lazy-loaded gallery: products.html
<html layout:decorator="layout/default" xmlns:layout="http://www.thymeleaf.org/" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Products Landing Page</title>
</head>
<body>
<div layout:fragment="content">
<h1>Products</h1>
<div data-gallery="lazyload"></div>
</div>
<div th:remove="tag" layout:fragment="footer-scripts">
<script type="text/javascript" src="/js/my_gallery.js"></script>
</div>
</body>
</html>
Our products page doesn't have much on it. Using the default decorator, this page overrides the page title in the head. Our content fragment includes a title in an h1 tag and an empty div with a data-gallery attribute. This attribute is what we'll use in our jQuery plugin to initialize the gallery.
The value is set to lazyload, so our plugin knows that we need to find the image IDs in some variable set somewhere. This could have easily been empty if the only thing our plugin supports is a lazyloaded gallery.
So the layout loads some default scripts and with cleverly placed layout:fragments, you allow certain sections of the site to load libraries independent of the rest.
Here's a basic Spring controller example, to work with our app: MyController.java
#Controller
public class MyController {
#RequestMapping("/products")
public String products(Model model) {
class Gallery {
public String theme;
public int[] images;
public String[] names;
public Gallery() {
this.theme = "basic";
this.images = new int[] {8,5,3,2};
this.names = new String[] {"Hey", "\"there's\"", "foo", "bar"};
}
}
model.addAttribute("gallery", new Gallery());
return "products";
}
}
The Gallery class was tossed inline in the products method, to simplify our example here. This could easily be a service or repository of some type that returns an array of identifiers, or whatever you need.
The jQuery plugin that we created, could look something like so: my_gallery.js
(function($) {
var MyGallery = function(element) {
this.$el = $(element);
this.type = this.$el.data('gallery');
if (this.type == 'lazyload') {
this.initLazyLoadedGallery();
}
};
MyGallery.prototype.initLazyLoadedGallery = function() {
// do some gallery loading magic here
// check the variables we loaded in our header
if (MY_APP.gallery.images.length) {
// we have images... sweet! let's fetch them and then do something cool.
PhotoGallery.load(MY_APP.gallery.images).loadTheme({
name: MY_APP.gallery.theme
});
// or if load() requires separate params
var imgs = MY_APP.gallery.images;
PhotoGallery.load(imgs[0],imgs[1],imgs[2],imgs[3]).loadTheme({
name: MY_APP.gallery.theme
});
}
};
// the plugin definition
$.fn.myGallery = function() {
return this.each(function() {
if (!$.data(this, 'myGallery')) {
$.data(this, 'myGallery', new MyGallery(this));
}
});
};
// initialize our gallery on all elements that have that data-gallery attribute
$('[data-gallery]').myGallery();
}(jQuery));
The final rendering of the products page would look like so:
<!doctype html>
<html>
<head>
<title>Products Landing Page</title>
<script type="text/javascript">
/*<![CDATA[*/
var MY_APP = {
contextPath: '/',
defaultTheme: null,
gallery: {
theme: 'basic',
images: [8,5,3,2],
names: ['Hey','\"there\'s\"','foo','bar']
}
};
/*]]>*/
</script>
</head>
<body>
<div>
<h1>Products</h1>
<div data-gallery="lazyload"></div>
</div>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/my_app.js"></script>
<script type="text/javascript" src="/js/my_gallery.js"></script>
</body>
</html>
As you can see, Thymeleaf does a pretty good job of translating your model to valid JS and actually adds the quotes where needed and escapes them as well. Once the page finishes rendering, with the jQuery plugin at the end of the file, everything needed to initialize the gallery should be loaded and ready to go.
This is not a perfect example, but I think it's a pretty straight-forward design pattern for a web app.
instead of ${pageHelper.documentReady} use ${pageHelper.documentReady}

DOM onLoad event without jquery

HTML code :
<html>
<head>
</head>
<body>
<script type="text/javascript" src="/js/colorbook.js"></script>
<script type="text/javascript">
book.init();
</script>
</body>
</html>
JS code :
var book = (function(){
init = function(){
console.log ( "initialized")
}return init();
}());
Question : The above code works. But I am unable to understand how?. Can any of JS guys help me here or guide me how should I start debug this code to understand it.
Ok so as per your comment. The Javascript you have there is all executed sequentially as the browser reads it from the incoming data stream. That being said, All javascript contained within the first script tag will be executed. Then the second script tag will be executed in sequence as well.
So right now you can look at the book.init() as being the last provided javascript call to be executed.
I tried your JS code in jsfiddle and could not get it to work check This Fiddle to see what I mean.
What is happening in your JS code is the last () at the end of the var book declaration executes the anonymous function which will print the line to the console. However from the code you supplied the book variable never gets a book.init() method. So once that call is reached it will throw an error of undefined.

How to inject dependencies in jasmine test for an angular item

Here is the test spec file:
describe('Test main controller', function(){
it('Should initialize value to Loading', function(){
$scope = {}
ctrl = new mainNavController($scope)
expect($scope.wksp_name).toBe('Loading')
})
})
Here is the controller file
function mainNavController($scope) {
$scope.wksp_name = 'Loading...'
$scope.$on('broadCastWkspNameEvent', function (e, args) {
$scope.wksp_name = args
})
}
mainNavController.$inject=['$scope']
But my test fails saying Object #<Object> has no method '$on'
I am using the basic setup of jasmine.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>
<link rel="shortcut icon" type="image/png" href="testlib/jasmine-1.2.0/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="testlib/jasmine-1.2.0/jasmine.css">
<script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine.js"></script>
<script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine-html.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="/static_files/js/test-specs/main-nav-spec.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="/static_files/js/common/jquery/latest.js"></script>
<script type="text/javascript" src="/static_files/js/common/angular/angular-1.0.1.min.js"></script>
<script type="text/javascript" src="/static_files/js/common/angular/angular-resource-1.0.1.min.js"></script>
<script type="text/javascript" src="/static_files/js/section/main-nav-controller.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>
What is it that I am doing wrong? I am not able to understand how this thing is supposed to work :)
The main problem with your test code is that it tries to create a controller's instance "by hand" using the new operator. When doing so AngularJS has no chance to inject dependencies. What you should be doing is to allow AngularJS inject dependencies:
var $scope, ctrl;
//you need to inject dependencies first
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
}));
it('Should initialize value to Loading', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.wksp_name).toBe('Loading...');
}));
Here is the link to a complete jsFiddle: http://jsfiddle.net/pkozlowski_opensource/7a7KR/3/
There are 2 things worth noting in the above example:
You can use the inject() method from the ngMock module to inject dependencies: https://docs.angularjs.org/api/ngMock/function/angular.mock.inject
To create a controller instance (that supports dependency injection) you would use the $controller service: http://docs.angularjs.org/api/ng.$controller
As the last remark: I would advise naming controllers starting with an uppercase letter - this way we won't confuse them with variable names.
Great answer by #pkozlowski.opensource. To elaborate a bit more... Sometimes it could be also handy to assert that $scope.$on was really called by your controller. In this case you can spy on $scope.$on as pointed out below:
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
spyOn($scope, '$on').andCallThrough();
}));
And then you can assert that $on was called with your event name and some function as arguments:
it('Should bind to "broadCastWkspNameEvent"', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.$on).toHaveBeenCalledWith('broadCastWkspNameEvent', jasmine.any(Function));
}));
I agree with pkozowski's response, but to answer your question more directly, you need to stub out '$on'
Your example would pass if your $scope looked like:
$scope = {
$on: function() {}
}

Custom validation of dijit textboxes

I was today seeking the net for information about textbox-validation, but even on Dojo-Homepage I couldn't get any useful information.
My problem: I've got a NumberSpinner, in which only numbers in steps of ten (10, 20, 30, ...) should be allowed. But I've got no idea how to set a validator for this. In the 'constraints'-statement there seems to be no possibility to do this. And I don't know how to use the validator-function so that the box shows me warning sign immediately when typing in somethin wrong.
Another question is how to check if any part of a form is not valid before sending it. Is there an attribute in every input/select-box like 'valid' to check them all at once?
Oh, one hint, I create all widgets programmatically.
Hopefully anyone out there can help me!!!
Best regards,
Robin
You can override the NumberSpinner's isValid() method. For example:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>class</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dijit/themes/soria/soria.css" />
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js"></script>
<script type="text/javascript">
dojo.config.parseOnLoad = true;
dojo.addOnLoad(function() {
dojo.require('dijit.form.NumberSpinner');
dojo.require('dojo.parser');
dojo.addOnLoad(function() {
new dijit.form.NumberSpinner({
isValid: function(isFocused) {
var value = parseFloat(this.attr('value'));
if (isNaN(value) || (value % 10 != 0)) {
return false;
} else {
return true;
}
}
}, 'here');
});
});
</script>
</head>
<body class="soria">
<div id="here"></div>
</body>
</html>
dijit.form.NumberSpinner is derived from dijit.form.ValidationTextBox, and as such it would accept the same arguments (see dijit.form.ValidationTextBox docs and inline docs in its source code). Just write a regular expression (as a string) that can validate your input. Something like that should do the trick:
var box = new dijit.form.NumberSpinner({
regExpGen: function(){ return "\\d+0"; }
}, "my_node");
You can also use the delta/smallDelta attribute for this. See the example at Dojo Campus

Resources