Testing Javascript that Manipulates the DOM - javascript

I've been looking into javascript test suites and I have found QUnit to be very interesting. I understand how to test computational code, but...
How do you test javascript applications written primarily for DOM manipulation?
it seems like testing the position/color/etc of DOM elements would be a moot point because you'd end up doing somethign like this:
$("li.my_element").css("background-color", "#f00");
and then in your test...
$(function() {
module("coloring");
test("test_my_element", function() {
var li_element_color = $("li.my_element").css('background-color');
equals(li_element_color, "#f00");
});
});
this just doesn't feel right because it basically just doing this:
var my_li= $("li.my_element");
my_li.css("background-color", "#f00");
if ( my_li.css("background-color") == "#f00" ) {
return true;
}
Am I nuts? How is this supposed to be done?
edit: the heart of the question:
I guess what I'm getting at is, I need to make sure the code isn't broken before I deploy, but the vast majority of it is UI helpers and ajax. How do I test that things are appearing correctly?
A few examples:
test that a JQuery UI dialog is appearing on top of all other elements
test that the drag-n-drop is working properly
test that the color of a droppable changes when an element is dropped on it
test that the ajax is all working properly
test that there are no extraneous commas that will break IE

I have found the Javascript/DOM tests, especially for the simple interactions that you are describing, are not that useful. You'll testing that things are set up right, and since jQuery is so declarative, your tests look a lot like your code.
My current thinking is that if you are writing larger JS components, it makes sense to pull out a set of interrelated behaviors both into a jQuery plugin and a set of tests for it.
But from the examples you mentioned, it sounds like you're really looking for a level of protection within your integrated website. A tool like Selenium will probably be more powerful and appropriate for you. In particular, it
can be automated
can run against multiple browsers, including IE
runs within the context of your web app and pages, so drag-n-drop can be tested where it really happens instead of in some test environment.
AJAX can be tested

Instead of testing the JQuery css function. Your test should mock the css function, and ensure that it is called only once with the correct color. The code tested should be yours, not the frameworks.

In addition to what Jason Harwig is saying, I would say that unit testing is a test to make sure that code is being run as expected. If you want to test that, then Jason is absolutely right about how you should do that. If you are wanting to run tests to check that the DOM manipulation is happening (UI testing) and not the actual code that is doing the DOM manipulation (unit testing), then you may want to check out something like Selenium, WatiN or Watir.

I'm guessing that many people test visually: i.e. they look at their browser's output on their monitor, to see whether it looks like the DOM was manipulated as expected.
If that needs to be an automated test case (eg. for regression testing), then maybe they record the output (like screen capture) and do something like compare two screenshots to see whether the results are the same.
Instead of capturing a screenshot, you could just capture the whole DOM, and do a side-by-side comparison of the captured DOM trees (which might be less error-prone that comparing pixels).

I test AJAX stuff like this:
Make the AJAX call
Set up a JavaScript timer
Check the DOM to see if the expected changes have happened
Now, it could be that the AJAX call hasn't returned before you do your check, but this is also useful test information; with an AJAX call, there is (usually) some time after which we'd call it a failure. As an example, if we're doing a suggestion popup, and it's taken 30 seconds to come back, that's a fail.

Related

How can I turn off CKEditor on certain platforms?

I've been reading a lot of places that show how to set CKEditor into a read-only mode, but that is not what I need.
For iOS/Android (or better: "small/mobile devices"), I'd like to actually turn it off so that I have a plain old <textarea> on those devices/platforms (we don't usually need the fancy stuff; it's just nice to have on a desktop so people can copy/paste from MS Word and not have it blow up).
Is there a setting I can configure; or can I at least run some Javascript and programmatically turn it off?
See CKEDITOR.env.isCompatible flag. You can always change it a bit (see the definition).
Alternatively, wrap your CKEDITOR.replace() (or inline()) call in some sort of conditional.

$.ready() before closing body

This is not a real coding question, more of a real-world statement.
I have previously noted that DOMReady events are slow, very slow. So, I noticed while browsing the jQuery source that the jQuery domeready event can be trigger using $.ready(). Then I thought, placing this simple execution script just before closing the body should trigger all the "onDomReady" listeners that where previoulsy attached. And yes, it works as expected:
<script>$.ready()</script>
</body>
Here are two examples, this one measures the ms spent while waiting for DOMReady:
http://jsbin.com/aqifon/10
As you can see, the DOMReady trigger is very natively slow, the user has to wait for a whole 200-300 milliseconds before the domready script kick in.
Anyway, if we place $.ready() just before closing the BODY tag we get this:
http://jsbin.com/aqifon/16
See the difference? By triggering domready manually, we can cut off 100-300 ms of execution delay. This is a major deal, because we can rely on jQuery to take care of DOM manipulations before we see them.
Now, to a question, I have never seen this being recommended or discussed before, but still it seems like a major performance issue. Everything is about optimizing the code itself, which is good of course, but it is in vain if the execution is delayed for such a long time that the user sees a "flash of "unjQueryedContent".
Any ideas why this is not discussed/recommended more frequently?
By triggering the event yourself, you are stating to your ready() handlers that your dom has been loaded BUT it may not have been! There is no short cutting the DOM ready event. If there is indeed a long wait time, then employ the amazing debugging tools of firebug, chrome, etc.... check your resources and their timing ques. It's all there in black and white and will indicate what is taking so long (the requests, the rendering, how many resources, etc.. )
Any ideas why this is not discussed/recommended more frequently?
Placing JavaScript just before </body> has been discussed a lot, and as you know it's recommended if you're looking for faster page loads. Manually triggering the jQuery ready handlers is in fact poorly discussed. Why? Well, I don't think there is one single objective answer to that, but I'll try to outline some possibilities here:
Performance is not the main goal of jQuery (anthough it's definitely a concern), and performance freaks will usually look for lighter libraries for cross-browser DOM manipulation and event handling, or roll their own.
It's an extra step, and it doesn't look clean. jQuery tries to be clean and elegant, and recommending an extra step to initialize scripts doesn't sound like something that's gonna happen. They recommend binding to ready, so recommending to force .ready() and ignoring the actual browser event looks "wrong". Whoever is concerned about that probably knows that initializing scripts right before </body> is faster.
Optimizing DOMContentLoaded sounds like a task for browser vendors. I'm not sure why it's slower, though, and maybe there's not much room for optimization – in my understanding, calling init scripts before </body> should always be the fastest way to initialize stuff (as it's executed immediately when parsing the container <script> tag, while browsers must finish parsing the whole file before triggering DOMContentLoaded).
You probably remember that not so long ago it was common practice to have <script> blocks scattered everywhere on the HTML. Then the Web Standards movement came, and recommended more sane and maintanable ways to do things. That included bootstraping scripts from a single place – initially, window.onload, which was then considered problematic for being slow, then DOMContentLoaded and its emulations for IE8 and below. However, we still see spaghetti-HTML with scripts everywhere on a daily basis here on StackOverflow. So I'm not sure if recommending placing scripts before the end of the body is a good call today, because it may be interpreted as a license to add scripts anywhere within the body.
Finally, if you're really concerned about loading your script fast, and your code does not manipulate the DOM, the fastest way to load it is to put it in the <head> before any stylesheets. And I'm stating that just to say that there's no silver bullet, no optimal way to init scripts that is the fastest and most elegant in every scenario. I think that's why the community sticks with recommending something that looks sane and tends to create more maintainable code, instead of other better performing alternatives.
Actually, placing a function call before </body> tag makes it pointless to use jQuery's ready(). Just put native JS-wrapper function call that contains calls of all other functions that should be called on document ready.
In general, it's a working (though somewhat littering HTML code and therefore unacceptable for perfectionists) alternative for situations when author does not need/want to use jQuery at all. In such situations though, I would prefer to use native DOMContentLoaded event handler that is supported by most of browsers including IE9+ (for IE8- we can use window.load() as an acceptable fallback).

Is there something better than document.execCommand?

When implementing a web-based rich-text editor, I read that document.execCommand is useful for performing operations on an HTML document (like making a selection bold). However, I need something a bit better. Specifically, I need to know exactly what text is added or removed from the innerHTML, and in what location (as an offset into the entire document's HTML representation).
I considered using the built in document.execCommand along side DOM4's mutation observer, but execCommand doesn't seem up to the task:
I don't see a way to "un-bold" a selection
the generated html seems to vary from browser to browser. (I'd like < span > tags not < b >, but consistency is more important)
and there's no information on what it does to handle redundantly nested/adjacent < span > tags.
Also, using mutation observer seems a bit overkill based on my needs.
My motivation: I'm trying to transmit document changes to the server periodically without re-transmitting the whole document. I'm sending the data as a collection of insertions and deletions upon the HTML representation. If someone knows a way to get this functionality out of, say, CKEditor (so I don't have to start from scratch), then I would love you forever.
Note: Performing a text diff is not an option, due to its poor performance on very large documents.
Otherwise, I'm not exactly afraid of trying to write something that does this. The methods provided by the DOM's range object would handle a lot of the heavy lifting. I'd also appreciate advice regarding this possibility.
There is one alternative to using execCommand - implementing the whole interaction of an editor including blinking of a cursor. And it has been done. Google does it in docs, but there's something free and open-source too. Cloud9 IDE http://c9.io has an implementation.
AFAIK, github uses that editor for some time now. And you surely can do anything under that, because there's no native code involved - like in execCommand
The repo is here: https://github.com/ajaxorg/cloud9 (it contains the whole IDE, you will need to find the code for the editor. )
Also - dom mutation events are deprecated. If you can drop support for old browsers, try mutation observer. If not - try to avoid detecting DOM changes at all and intercept changes in the editor's implementation. It might be the way to go for the new browsers too.
There is Trix rich text editor, from their description it looks like avoiding inconsistent execCommand is the whole point of the project.
It seems the new standard will be Input Events Level 2. To me it looks like it will be a revised improved version of execCommand.

How to find a rare bug?

My application contains a bug, which makes script run infinitelly long. When I force script to stop, all jQuery UI elements don't answer to my actions, nor application answers to keypresses.
If I choose to open Firebug, it requires reloading page and all current application state is lost.
The thing is I can't reproduce this bug and it's kinda driving me crazy. How to find and fix such slick bug?
UPDATE. Thanks all of you for the advice. But the problem is that I can't figure out when bug happens and, hence, can't reproduce it. That's why standard procedures won't work in my case.
I have examined every while loop and recursive function calls, but haven't figured out the problem yet.
Publishing the code isn't a good idea — code listing is huge and rather complicated (a game).
POSSIBLE SOLUTION. I'll follow one of the published hints and will try to consolelog all functions that might be causing the problem. Hope it helps.
There are two main approaches for dealing with this:
Set break points and step through your code
Start commenting out certain sections of code. Once you comment out a section that eliminates the bug, start commenting out smaller pieces of that section until you arrive at the line of code that is causing the issue.
It might also help to know what you are looking for. An infinitely running script will generally result from one of two things:
A loop that never terminates.
A function that calls itself
Keeping an eye out for these things might help the debugging process go a bit more quickly. Good luck!
break your code into chunks and determine which one causes failure. like for example, if you have a form with several fields that have date-pickers and auto-completes, take them apart one by one. zero-in on who causes it.
use the debugger timeline. cruise around your site with the timeline recording your page performance. you will see in the timeline which task it taking too long. the browser may crash when you find the bug, but you will at least see a glimpse of what happened when.
try to recreate your actions. do some step-by-step checklist on how you navigate through. this way, you can trace in the code the possible path your script took when you did your move. if only JS had a back-trace like PHP, this would be easier.
try to review your code. things like loops, recursions or even two functions calling each other can cause this never-ending loop.
if you could, use a VCS tool like SVN or GIT. you can easily build n' break your code without the worry of losing a working version. you can revert easily if you use VCS.
Infinite long time, means,
I think some function is getting called recursively or some event is getting fired recursively. To track it down,
Try to put console.log in all the functions, which are getting called from window.onload or document.ready (if you are using jquery).
Use Firebug's profile, which will tell you every function call that is happening.
I always look for functions that might be being called too often or loops that never stop looping. Then, keep track of how many times your suspected functions/loops execute. Example:
var runCount = 0;
function guiltyLookingFunction(params)
{
runCount++; //increase by 1 every time this function runs
if (runCount>1000) //if this has run some insane number of times
alert("this function is the that's running wild!");
//the rest of your function's code
//same thing with loops within functions:
var loopCount = 0;
while (0!=1) //this will always be true, so the loop won't stop!
{
loopCount++;
if (loopCount>1000)
alert("this loop is to blame!");
//the rest of your loop
}
}
(replace "this function/loop" with some specific identifier if you're monitoring multiple suspects)
A) Use WebKit's (Safari, Chrome, Chromium) inspector instead of firebug - No more reload, yay!
B) Set some debug output along the way that will help narrow your problem down to the perpetrator.
Firebug. Reloading? Didn't you try to open Firebug before page loading?

How to ignore certain script files / lines when debugging?

I'm trying to debug some JavaScript, I want to find out what code gets executed when I hover over a certain div element (I've got no idea which bit of code, because there's no direct 'onmouseover' - I think there's a jQuery selector in place somewhere?).
Usually I'd use the "Break All" / "Break On Next" facility provided by Developer Tools / Firebug, but my problem is that other code (tickers, mouse movement listeners etc.) immediately gets caught instead.
What I'd like to do is tell the debugger to ignore certain JavaScript files or individual lines, so that it won't stop on code I'm not interested in or have ruled out. Is there any way to achieve that in IE (spit, spit!) - or could you suggest a better approach?
In FireFox this feature is called "Black boxing" and will be available with FireFox 25. It let's do exactly what you where looking for.
This feature was also introduced to Chrome (v30+) although it's tougher to find/configure. It's called "skip through sources with particular names" and Collin Miller did an excellent job in describing how to configure it.
Normally I'm for putting answers and howtos here instead of links but it would just end in me copying Collin's post.
Looks like you're looking for Visual Event.
You might want to take a look at Paul Irish's Re-Introduction to the Chrome Developer Tools, in particular the Timeline section (starts around 15 minutes into the video.)
You can start recording all javascript events - function executions (with source lines etc) and debug based on what events fired. There are other really handy debugging tools hiding in that google IO talk that can help you solve this problem as well.
If you're pretty sure it's a jQuery event handler you can try to poke around with the jQuery events.
This will overwrite all the click handlers (replace with the type you're interested in) and log out something before each event handler is called:
var elem = document.body; // replace with your div
// wrap all click events:
$.each($._data(elem).events.click, function(i, v) {
var h = v.handler;
v.handler = function() {
// or use 'alert' or something here if no Dev Tools
console.log('calling event: '+ i);
console.log('event handler src: '+ h.toString());
h.apply(h, arguments);
};
})
Then try calling the event type directly through jQuery to rule out that type:
$('#your_div').click()
You can use JavaScript Deobfuscator extension in Firefox: https://addons.mozilla.org/addon/javascript-deobfuscator/. It uses the same debugging API as Firebug but presents the results differently.
In the "Executed scripts" tab it will show you all code that is running. If some unrelated code is executing as well it is usually easy enough to skip. But you can also tweak the default filters to limit the amount of code being displayed.
If using are using IE 7.0 onwards, you should have developer toolbar from where you can debug. Just use breakpoint where you need, rest of the code will not stop.
Alternatavely you can define other applications like Interdev/ Visual Studio.net for debugging purpose too.

Categories

Resources