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
scripttag into theheadsection of theiframe. - The tests always use
JSANto loadTest.Builder, either directly or by loading a library that depends on it (likeTest.More. Test.Builderdetects when it’s being run in a browser and sets anonloadevent handler to end the execution of tests.- For the first two test files,
Test.Builderloads and runs, and sets up theonloadevent handler, and it properly executes when the test finish. - But in the third test, the
onloadevent handler seems to run beforeTest.Builderhas finished execution or even loading! As such, it cannot get access to theTest.Builderclass to finish the tests, and throws an exception:Error: this.Test has no properties
, wherethisis theiframewindow 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
is the name of the variable that is holding the buffercontentWindow 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 browseralert("Setup: buffer")during the execution ofTest.Builderfor async.js, where "buffer" is the name of theiframeelement.alert("Onload: buffer")for async.js, during the execution of theonloadeventbad_plan.js.......
output to browseralert("Setup: buffer")during the execution ofTest.Builderfor bad_plan.jsalert("Onload: buffer")for bad_plan.js, during the execution of theonloadeventbuffer.js........
output to browseralert("Catch: buffer")output from catching the exception in theonloadhandler for buffer.js, which, of course,Test.builderhasn’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:
Theory wrote:
Larry wrote:
Theory wrote: