home :: computers :: programming :: javascript :: need js genius

Plea for Help from JavaScript Geniuses

I’ve been working for some time to get pure .js test files working with Test.Simple. In principal, it’s simple: The Browser harness simply constructs a hidden iframe, and if the test script ends in .js, it uses document.write() for that iframe to write out a new HTML document that includes the test script via a script tag. It can also load other scripts specified by the user in the index.html file that runs the harness.

I got it working, and then converted all of Test.Simple’s own tests over to .js files, at which point it got all weird. The tests were dying after the third test file was loaded and run. After weeks of on and off debugging, I’ve reduced the problem enough to find the following:

  • I’m using JSAN to load dependencies in the test scripts themselves. The browser harness loads it by writing a script tag into the head section of the iframe.
  • The tests always use JSAN to load Test.Builder, either directly or by loading a library that depends on it (like Test.More.
  • Test.Builder detects when it’s being run in a browser and sets an onload event handler to end the execution of tests.
  • For the first two test files, Test.Builder loads and runs, and sets up the onload event handler, and it properly executes when the test finish.
  • But in the third test, the onload event handler seems to run before Test.Builder has finished execution or even loading! As such, it cannot get access to the Test.Builder class to finish the tests, and throws an exception: Error: this.Test has no properties, where this is the iframe window object.

The only thing I can guess is that it’s retaining the onload event handler for the previous test file, even if I put delete buffer.onload before writing out the HTML to load the test file! (Note that buffer is the name of the variable that is holding the contentWindow attribute of the iframe object.) You can observe this behavior for yourself by running the tests now. They don’t work in Safari at all (I code to Firefox and then port to the other browsers), but Firefox demonstrates the issue. I have alert()s that run just before Test.Builder sets up the onload event handler, and then inside the event handler, either when its run or when it catches an exception (but before it rethrows it). The order of execution, you’ll note, is as follows:

  • async.js.......... output to browser
  • alert("Setup: buffer") during the execution of Test.Builder for async.js, where "buffer" is the name of the iframe element.
  • alert("Onload: buffer") for async.js, during the execution of the onload event
  • bad_plan.js....... output to browser
  • alert("Setup: buffer") during the execution of Test.Builder for bad_plan.js
  • alert("Onload: buffer") for bad_plan.js, during the execution of the onload event
  • buffer.js........ output to browser
  • alert("Catch: buffer") output from catching the exception in the onload handler for buffer.js, which, of course, Test.builder hasn’t set up yet!

If I don’t rethrow the exception, it then runs the code in Test.Builder that sets up the onload handler. In other words, the onload handler runs before it has been created. Huh?

The nearest to a workaround that I’ve found is to delete the iframe element after each test and create a new one. The errors are still thrown, but all tests seem to pass anyway. It doesn’t seem to like the old-style .html test files, though; it hangs on them without throwing any error at all. Grrrr.

So, are you a JavaScript genius? Do you know how the browser, DOM, and frames work and interact better than you know your own family? If so, please, please give me a hint as to what I can do to fix this problem so that I can get a new version of Test.Simple out ASAP. Thanks!

Update: I forgot to mention that the in-progress source code for Test.Simple with support for .js test files can be downloaded here, so that you can play with it on your own system. Thanks!

Comments & Trackbacks

ty wrote:

Not a genius and probably completely off the mark, but my assumptions about how javascript and frames work was recently challenged and it seems similar (if not then pls ignore). I thought that loading and external javascript file and having the javascript inline were equivalent, but it seems that the page continues to load after it encounters the script tag while the external javascript is loaded and executed (I presume by another thread). Once the the page loads the onload event is run regardless of if the external javascript has finished. I have been doing javascript for a few years and this is completely at odds with my intuition about how it should work. I also encountered the behaviour inside an iframe in firefox. Not sure if this behaviour is mandated by any particular standard, is present accross browsers, or likely to change(/get fixed?) in the future. I worked around this by using a status variable which is set at the end of the script, and used setInterval to wait for it. YMMV.

Theory wrote:

ty

Thanks for the info. I am aware that there can be async problems with scripts loaded via script tags, annoying as that may be. My problem was more basic than that: Getting the scripts not to hang! But I got some help from another source, on IRC, and now I have pure .js tests working in Firefox, Safari, Opera, and IE (though not with XP SP 2). New release going out now. I'll post an announcement shortly.

Thanks for validating that the script loading issue is significant, though! I think it's one of the main reasons that JSAN will continue to use synchronous XMLHttpRequest to load libraries for the forseeable future.

—Theory

Larry wrote:

IE hangs (sometimes) on assignment of new Option

Have you ever encountered a situation in which IE hangs right on a line on which a new Option-object is being assigned to the options-array of a select-object? It's especially weird, since it seems to happen only when the page is loaded as part of a kind of "bounce-back" in response to a form-validation error (executed on the server-side). That is, whenever the same page is intially loaded, it works fine; it's only upon "bounce-back" that it consistently hangs, on a line on which a new OPTION is being added to a SELECT. I think it's dangerous that the script isn't run via onload, but rather is run, so to speak, "inline" at the very bottom of the page; furthermore, the script is pulled in via a script-tag (JavaScript-include, as I think of it) that's situated BELOW the closing HTML-tag. (BTW, somebody else wrote that code; I'm just trying to use it and maintain it.) I have yet to experiment with invoking that code via onload and/or pulling the script in, say, right before the closing BODY-tag. Any feedback would be appreciated. Thanks.

Theory wrote:

Larry,

I'm not familiar with the scenario you describe, but it's valid to put the <script> just inside the closing </body> tag. It's not valid for it to be outside of the closing </body>, but it doesn't surprise me that most browsers will accept it anyway.

—Theory

Powered by KinoSearch