FYI, my post to the JsUnit group.

-Dan

      -unless you love someone-
    -nothing else makes any sense-
           e.e. cummings

---------- Forwarded message ----------
Date: Wed, 30 Nov 2005 15:06:56 -0800 (Pacific Standard Time)
From: Dan Fabulich <[EMAIL PROTECTED]>
Reply-To: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Subject: [jsunit] AJAXUnit?


Since it looks like many people here have had to kludge in something to
test AJAX and other asynchronous JavaScript events, I thought I'd mention
one of my favorite solutions.

When you initiate an asynchronous call like window.setTimeout,
XMLHTTPRequest.send, or change location.href, what you'd want to do is
something like this:

   function testFoo() {
      myrequest.send();
      while (myrequest.readyState < 4) {
         failIfTimedOut();
         sleep(10);
      }
      assertEquals(200, myrequest.status);
   }

Unfortunately, you can't actually write the test this way, because JavaScript has no native sleep() function. You can register a callback function with XMLHttpRequest's onReadyStateChange field, but even if your code does get called back, it will be too late for testFoo, which will return immediately unless it can somehow find a way to wait for the callback.

JavaScript has no native sleep() function, but Java does. It's really easy to expose this as an applet:

import java.applet.Applet;

public class Sleeper extends Applet {
   public void sleep(long millis) throws InterruptedException {
     Thread.sleep(millis);
   }
}

Put this applet in your HTML page like this:

<APPLET CODE="Sleeper" WIDTH=0 HEIGHT=0 NAME="sleeper" ID="sleeper">
</APPLET>

Then you can invoke document.sleeper.sleep(500) to synchronously sleep. That allows you to, for example, register event handlers that do nothing but set a flag declaring that the event is done. You can use this to synchronously sleep-and-poll those flags until your asynchronous events appear to be done, and then take action afterwards.

I should point out that I couldn't get this to work in Internet Explorer 6.0 on XP SP2; the only way I found to do it was to write an ActiveX control that did the same thing in C#.

// Sleeper.cs
using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace kludge
{

      [ClassInterface(ClassInterfaceType.AutoDual)]
      public class Sleeper
      {
            public void sleep(int milliSeconds)
            {
                  Thread.Sleep(milliSeconds);
            }
      }
}

Then you can use the .NET Framework to compile it (no VS.NET required)
csc /t:library Sleeper.cs
regasm Sleeper.dll /tlb:SleeperNet.dll /codebase

and finally load it up in your JavaScript with:

var IESleeper = new ActiveXObject("kludge.Sleeper");
IESleeper.sleep(500);


It seems to me that the only other way to handle this problem is to make JsUnit itself more friendly to asynchronous events throughout the test lifecycle. The most natural way I can see to accomplish this is to make a special JsUnit-based setTimeout() method; if you call the JsUnit setTimeout() in a test, JsUnit would invoke your code in a try-block, and handle any errors/failures.

The problem with this, as I'd mentioned in my earlier post, is that it means that everything has to be broken into parts... it's like setUpPage vs. setUpPageComplete, but *everywhere*. Your tests will have to start keeping track: is this the first time I'm being invoked? If so, open the window. Or is it the second time? In that case, do XYZ. Is this the third time I'm being invoked...? Writing good tests like this is really hard, basically because writing asynchronous code is hard.


Anyway, perhaps either or both of these should become an official part of the JsUnit framework? The world cries out for AJAXUnit.

-Dan
_______________________________________________
Selenium-users mailing list
Selenium-users@lists.public.thoughtworks.org
http://lists.public.thoughtworks.org/mailman/listinfo/selenium-users

Reply via email to