Automating Javascript unit testing... where to start? - javascript

I have a website that's build using JS for the client-side and PHP for the backend with a MySQL backing DB. I started unit testing everything, and the back-end was fairly straightforward using PHPUnit.
In the same spirit, I wanted to start testing the client-side and opted for QUnit. However, we're using Kendo UI and I'm a little lost as to how I could automate my tests without practically reinventing the wheel.
Say I have a modify.js file, where after I define everything I have the following jQuery:
$(document).ready(function() {
$("#user-menu").kendoMenu();
var modify = $('#modify');
kendo.bind(modify, modifyViewModel);
kendo.bind($('#numTagWindow'), numTagWindow);
modifyViewModel.initForm();
$(window).on("resize", function() {
kendo.resize($("#trip"));
});
});
Here, modify.php is an html file with some PHP and corresponds to the view that users get when they go to modify some corresponding setting. In a separate jsTest.js file which is incuded in modify.php, I have all my QUnit tests pertaining to modify.js.
My question is the following: What would be the standard approach for unit testing here, automated or otherwise? As it stands, since the same HTML page is being used for numerous tests my only current option is manually trying out every single option to see if the assertions pass.
In the case where a said function depends on the type of pre-selected input, this gets even worse. I'm forced to put a different number of expected assertions based on input (admittedly, this may be a design flaw).
How should I approach this? Would it be possible to just 'reset' the page using multiple $(document).ready's and run the tests in that manner? In that case, what would be the easiest way to provide the user input to the client-side code?

I haven't ever tested an app with KendoUI before, but I assume it's similar to any other front-end library... that is, you can either use whatever built in tools they have, mock out the library, or do more "integration" testing rather than unit testing. For your minimal example above mocking isn't so bad, but you can imagine it getting out of hand. As such, I'd say integration testing is best, and you can use QUnit for that (along with jQuery), you just have to "write" all of the actions you're testing.
Of course, you also need to have some strategy for making the tests atomic by resetting the HTML blocks, or separating the various blocks into different test files, or something else...
Here is an uber basic example of a QUnit test file with an html fixture that gets reset after each test. Note that by using the document.ready() call in your source code you basically negate the ability to do any of this. If you strip that out and an init() method of some sort things will work much better.
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="lib/qunit-1.14.0.css" />
</head>
<body>
<div id="qunit"></div> <!-- required! -->
<div id="qunit-fixture">
<!-- HTML to be reset for each test -->
<div id="user-menu"> <!-- whatever you need in here --> </div>
<!-- whatever other HTML you need for these tests -->
</div>
<script src="lib/qunit-1.14.0.js"></script>
<script src="path/to/source-code.js"></script>
<script>
QUnit.test("Test some trigger", function(assert) {
myCode.init(); // used to be in your document.ready()
$("#someTriggerButton").click();
assert.ok($("#someElement").hasClass("foobar"), "Ensure the element has the correct class after clicking trigger");
});
// Note that after this test runs, before the next test runs,
// the HTML inside of #qunit-fixture will be reset to its value when freshly loaded
QUnit.test("Another test", function(assert) {
// ...
});
</script>
</body>
</html>
So there's something to start with... This is intended to be used with HTML fragments, not entire pages. Of course, there are lots of other ways to do things. Unfortunately, your question is a bit too vague to really give you a specific "solution". If you try something out and have issues, please post another question on here and we'll try to help.

Related

Markup validation when page is generated with AngularJS

We have a single page application created using AngularJS. We'd like to validate markup of that application. The problem is that markup is mostly generated with script, so that if we pass source code to validator, the result is only partial.
Currently we're looking into testing the page in the following way.
Open the page with Selenium web automation library.
Do some actions.
Dump current HTML to file.
Process it with standalone validator.
It's quite time consuming to implement this flow, as we would need to hardcode all the ways to use an application, so I'd like to ask: is there any other ways to do it?
With AngularJS Your should NOT have to do validate every variation of your page as DOM changes with script in your Single Page Application as long as you stick with AngularJS programming model and stick to the following:-
Validate every HTML file/fragment.
These are Angular templates/partials OR any HTML files you may have (index.html).
Use grunt based html validator plugins like this so that grunt workflow can ensure that the HTML is valid even before it is committed in to your source code repository. Such plugins can validate HTML fragments.
Use built-in AngularJS directives to manipulate the DOM.
e.g. ngSwitch, ngView, ngIf etc. instead of any custom stuff using jQuery or other mechanism.
AngularJS already ensures a valid HTML DOM. That means your resulting HTML is always going to be valid.
Have you consider using Angular e2e:
http://docs.angularjs.org/guide/dev_guide.e2e-testing
This allows you access to get/validate elements from html like:
expect(element('#email').html()).toBe('something');
From Angular Documentation using jazmine:
describe('Buzz Client', function() {
it('should filter results', function() {
input('user').enter('jacksparrow');
element(':button').click();
expect(repeater('ul li').count()).toEqual(10);
input('filterText').enter('Bees');
expect(repeater('ul li').count()).toEqual(1);
});
});
Update 1
Then you can try something like:
https://github.com/peterjwest/html_validator/blob/master/demo.js
I call this GUI level Testing. Visual Studio has an excellent browser recording and playback tool, which allow a tester to create Automated tests which validate anything the tester wants.
Here's a video: https://onedrive.live.com/?cid=ae5cd7309cccc43c&id=AE5CD7309CCCC43C%21183&sff=1&authkey=%21ANqaLtCZbtJrImU&v=3
You'll need to have the Premium edition to do this. In addition, I've heard good reports about Selenium, in fact, MSFT themselves have endorsed it.

remove 2nd instance of javascript that is loaded

I have 2 instances of javascript being load in Joomla in my 'head'.
The 1st is from the template.
The 2nd is from a component.
I need to remove the 2nd instance as below:
<!-- keep this one -->
<script src="//code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script>
<!-- remove this one -->
<script src="//code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script>
How would I do this with PHP?
Edit:
Can I do something like this (not a php dude) to remove the 2nd instance?
$string='<script src="//code.jquery.com/jquery-1.10.2.min.js" type="text/javascript"></script>' ;
$string_array=explode(",","$string");
$output[]=$string_array[0];
for($i=1;$i<count($string_array);$i++){
if(!in_array($string_array[$i],$output)){
$output[]=$string_array[$i];
}
}
print implode(",",$output);
First point of note here is that neither bit bit of code is particularly well written - both will block the html loading for a significant amount of time even if it's fetched from local cache. And one of the main reasons for using a CMS is so that you minimise the number of calls to resources outside the HTML to enhance performance.
Can I do something like this
Yes, but you need to enable output buffering and hook it into the code at the right point which will be much more of a PITA to maintain than changing the plugin/template.
Alternatively you could implement it as an Apache output filter - but (AFAIK) it's not (currently) possible to invoke fastCGI or mod_php as an output filter. You could implement a simple HTTP proxy script as the end point for requests and rewrite the HTML there.
It's possible that a tool for merging requests (such as mod_pagespeed) would automatically remove the duplicate request (although the documentation for mod_pagespeed's combine_javascript doesn't say how it deals with such a scenario).

Embedded Javascript missing from Google Apps Script Web App serverHandler output

I'm trying to embed some JavaScript into the output of a Google Apps Script that is running as a web app, but I can't find any evidence of my script tags or jQuery loading in the output, so I think it is getting stripped out, I assume, by Caja.
I'm adding the JavaScript by creating an HTMLOutputObject from a file, like this:
app.add(app.createHTML(HtmlService.createHtmlOutputFromFile("order_form_javascript").getContent()));
Maybe it is worth mentioning here that the javascript is added this way in a serverHandler attached to a listBox change event - NOT in the initial doGet() function - I'm not sure if that makes a difference.
The content of the order_form_javascript.html file is:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<h3>Javascript!</h3>
<script type="text/javascript">
alert ("script ran");
$(function() {
alert ("function ran");
$('.order_table tr:hidden').show();
});
</script>
The H3 tags are in the output, but no script tags appear, no alert boxes pop up and jQuery is undefined.
I tried this code on the Caja playground and it seems to work. So I think that I must be inserting the javascript incorrectly, or missing something obvious.
Thanks, in advance, for any suggestions you can offer.
I'm not deeply familiar with Apps Script, but it looks like you are trying to mix Ui Service (add, createHTML) and Html Service in the same page. This is not supported — you must choose one or the other for the entire page.
A side note on troubleshooting: Caja never inserts the script you write in the DOM (doing so would break the sandbox). In NATIVE sandbox mode you may see <script> elements with empty or stub contents, though. So, the absence of scripts does not itself indicate a problem.
Following Kevin Reids tips that Caja wouldn't likely show script tags anyway, as this would break sandboxing, and also that HtmlService and UiService may be incompatible in the same script, I updated my code to the following:
var js = HtmlService.createHtmlOutputFromFile("order_form_javascript").getContent();
Logger.log(js); //check that HtmlService generates the script properly.
app.add(app.createHTML(js));
Looking in the logs, I can clearly see that HtmlService is returning my HTML file's content verbatim:
[13-07-24 10:02:28:879 BST] <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<h3>Javascript!</h3>
<script type="text/javascript">
alert ("script ran");
$(function() {
alert ("function ran");
$('.order_table tr:hidden').show();
});
</script>
Which makes me think that maybe I could use this method to output arbitrary HTML without writing it all in code, but I digress.
This lead me to the app.createHTML([String]) method and, according to the documentation here, HTML widgets can't actually contain <script> tags. So that's where they are being stripped out. It turns out I should have read the manual. How embarrassing.
The two possible solutions I can think of are;
Re-write my web app using HtmlService instead of UiService, which I think would allow more arbitrary html and scripts from HTML files in the project.
Since my JavaScript is going to be event driven and very simple, I could also use a clientHandler to perform the necessary actions and continue using the UiService for my web app.
I'm going to start with the clientHandler approach.

Using Jasmine to test embedded javascript code

I have code that is embedded in html as follows:
<script type="text/javascript">
function add(a, b) {
return a+b;
}
</script>
And I was wondering if anyone knew if this was possible to test using Jasmine and the JQuery fixtures? I am new to Jasmine and don't understand how to test this kind of code.
Thanks.
I think #pawlik is suggesting it is better belonging in it's own .js file. The only option I considered to answer your question is to source this file as a fixture (using the loadFixtures('file') method) but you normally do this with fragments (nothing that contains html, head or body tags) and if there are any on DOM ready events which are fired in script tags or includes they may not place nicely with jasmine.
Saying you can't change the file may not mean you cannot change the structure (ie. push it out to a separate script file and refer to that in the main HTML page.) In many cases you should refactor the structure of your code to facilitate testing.
Since you are new to jasmine, when writing tests you tend to test javascript functions/methods on their own, or with fragments of HTML (if you are doing DOM-based testing) as fixtures. You wouldn't normally use a complete HTML page and write tests for it, this is more of an end-to-end / functional test and is not the primary goal of jasmine.
BTW you are missing the end double-quote of "text/javascript <--

What is the best way to organize JS code in webapps where the main "meat" is still server side?

When building webapps with MVC web framworks like Django, Kohana, Rails and the like, I put together the application without JS-driven components initially, and then add them afterwards as "improvements" to the UI.
This approach leads to non-intrusive JS, but I don't have a good "standard" way of how to go about organizing the JS work. Most of the JS I write in apps like these are 10-30 line JQuery snippets that hook into some very specific part of the UI.
So far I often end up inlining these things together with the part of the UI they manage. This makes me feel dirty, I'd like to keep the JS code as organized as the python / php / ruby code, I'd like for it to be testable and I'd like for it to be reusable.
What is the best way to go about organizing JS code in a setup like this, where we're not building a full-blown JS client app, and the main meat is still server side?
I am also very interested in what other people have to say about this. The approach I've taken is to use object literal notation to store the bulk of the function, and store these in one file included on all pages (the library)
uiHelper = {
inputDefault:function(defaulttext){
// function to swap default text into input elements
},
loadSubSection:function(url){
// loads new page using ajax instead of refreshing page
},
makeSortable:function(){
// apply jQuery UI sortable properties to list and remove non javascript controls
}
}
Then I include a .js file on any page that needs to use the library that ties the elements on that page to the function in the library. I've tried to make each function as reuseable as possible and sometimes the event binding function on the page calls several of my library functions.
$(document).ready(function(){
$('#mybutton').live('click',uiHelper.loadSubSection);
//more complicated helper
$('#myotherbutton').live('click',function(){
uiHelper.doThisThing;
uiHelper.andThisThing;
});
});
edit: using jsDoc http://jsdoc.sourceforge.net/ notation for commenting for these functions can produce documentation for the 'library' and helps keep your code easy to read (functions split by comments).
The following question is along similar lines to your own - you should check it out...
Commonly accepted best practices around code organization in JavaScript
When dealing with JS code, you should first analyze whether it will be used right away when the page loads. If it's not used right away (meaning the user must do something to invoke it) you should package this into a JS file and include it later so the load time is perceived faster for the user. This means that anything that the user will sees should go first and JS related to the functionality should be imported near the end of the file.
Download this tool to analyze your website: http://getfirebug.com/
If the JS code is small enough, it should just be inline with the HTML.
Hope that helps a bit.
For quick little user interface things like that I put everything into a single javascript file that I include on every page. Then in the javascript file I check what exists on the page and run code accordingly. I might have this in UIMagic.js for example. I have jQuery, so excuse those jQuery-isms if they aren't familiar to you.
function setupMenuHover() {
if ($("li.menu").length) { // The page has a menu
$("li.menu").hover(function() { ... }, function() { ... });
}
}
$(setupMenuHover);
function setupFacebookWizbang() {
if (typeof FB != "undefined") { // The page has Facebook's Javascript API
...
}
}
$(setupFacebookWizbang);
I've found this to be a sane enough approach.
My preferred method is to store inline javascript in it's own file (so that I can edit it easily with syntax highlighting etc.), and then include it on the page by loading the contents directly:
'<script type="text/javascript">'+open('~/js/page-inline.js').read()+'</script>'
This may not perform well though, unless your templating library can cache this sort of thing.
With Django you might be able to just include the js file:
<script type="text/javascript">
{% include "js/page-inline.js" %}
</script>
Not sure if that caches the output.
If you are still worried about being 'dirty', then you could check out the following projects, which try to bridge the server/client side language mismatch:
http://pyjs.org/ (Python generating JavaScript)
http://code.google.com/webtoolkit/ (Java generating JavaScript)
http://nodejs.org/ (JavaScript all the way!)

Categories

Resources