Sunday, December 5, 2010

UI Test automation using Watij, Webspec : Handling ModalDialogs

Since long I have been trying a complete & cheap (free) tool to automate the UI based testing. Since when I learnt about automated testing , I knew about screen recording based test technologies such as Winrunner & HP QuickTest Professionalwhich also supports scripting using a proprietary Test Script Language(TST). Though QuickTest Professional serves most of the purpose I was looking for, but I didn't like it because of two primary reasons. First being its high license cost and second its proprietary software which needs to be installed on developer's/tester's PC.

I kept searching for better solutions as per my needs (free/cheap solution) and got a lot of hope when I first learnt about recording based UI testing supported by Selenium, I was very excited. Later Selenium started supporting script based test scenario creation which was a big aid to create the automated test cases. Later I learnt about about Java based test tool Watij. This was a big improvement in the world of UI based automation testing.

Creating test cases in Watij or Selenium is very easy. If you have clear understanding of DOM, it becomes much more simpler. Here are some examples of sample test script statements.

IE ie = new IE();
ie.start("http://yogendrakrsingh.blogspot.com/");
assertTrue(ie.containsText("/MY LEARNINGS/"));

To set some text field value, you can simply write as ie.textField(id,"myTextId").set("My Value");
To click some button, you can simply write as ie.button(value,"My Botton").click();

Similarly in Selenium a simple test script could be as following:

selenium.open("http://yogendrakrsingh.blogspot.com/");
selenium.waitForPageToLoad("1000");
verifyTrue(selenium.isTextPresent("MY LEARNINGS"));

To set some text field value, you can simply write as selenium.type("myTextId", "My Value");
To click some button, you can simply write as selenium.click("myButton");

Though both Selenium and Watij were very easy to use, both were having limitation in handling Modal dialogs. This limitation proved fatal and all my attempts to use either of them(Selenium/Watij) as automated UI test tools became unsuccessful. Some time back, I learnt the trick to handle ModalDialog using Watij vr. 3.2.1. To handle a Modal Dialog in Watij, created a method in watij.runtime.ie.IE java file as below:

    public ModalDialog modalDialogNested() throws Exception { 
      waitUntilReady();
      final OleMessageLoop modalDialogMessageLoop = new OleMessageLoop("modalDialogMessageLoop"); 
      final ModalDialogFinder modalDialogFinder = new ModalDialogFinder((int) hwnd, modalDialogMessageLoop); 
      modalDialogMessageLoop.doStart(); 
      modalDialogMessageLoop.doInvokeAndWait(modalDialogFinder); 
      return new IEModalDialog(modalDialogFinder.getHtmlDocument(), 
                                             modalDialogMessageLoop, modalDialogFinder.getIE()); 
    }

Then another trick is to open a modal dialog in a new Java Thread so that main thread is not in waiting state. This provides you the control to write and execute further UI test script in the modal dialog. Sample test script could be as below:

    ie.frame(id,"testFrame").textField(id, "inpField").set("Hello! Test very success");
        new Thread(new Runnable() {
            public void run() {
                try {
                    ie.button(id,"mybutton").click();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();


        ModalDialog modalDialog = ie.modalDialogNested();
        modalDialog.textField(id, "inpField").set("Hello! test success");
        final Button myButton =  modalDialog.button(id,"mybutton");
        new Thread(new Runnable() {
            public void run() {
                try {
                 myButton.click();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
   
        ModalDialog modalDialogChild = modalDialog.modalDialog();
        modalDialogChild.textField(id, "inpField").set("Hello! Test success ultimate");
        modalDialogChild.button(value, "Close").click();
        modalDialog.button(value, "Close").click();

Thus I was able to overcome the Modal Dialog limitation of Watij and all set to use Watij as complete UI automation test tool.

Webspec is newer version of Watij with more simpler and powerful syntax. This works on IE, Firefox and Safari with platform support of Windows, Linux and Mac. Along with its simpler command based statements, its also supports the power of JQuery.

To perform the above kind of tasks through WebSpec, we can write statements as below:

WebSpec spec = new WebSpec().ie();
spec.open("http://yogendrakrsingh.blogspot.com/");
spec.find("title").with("My Learnings").shouldExist();

To handle the modal dialog in Webspec, you need to implement html dialog listener by following steps below:

com.jniwrapper.win32.ie.Browser browser = spec.getBrowser().getPeer();
browser.setHtmlDialogListener(new MyHtmlDialogListener(){
        public void show(HtmlDialogEvent event){
             HTMLDialog myDialog = event.getDialog();
             HTMLDocument dialogDocument = myDialog.getDocument();
             //perform your steps in the modal dailog document here
        }
});


Webspec is currently in active development. We need to refer their latest release documents to get familiar with latest updates. 

10 comments:

  1. Hi,
    I tried use the code with webspec but it doesn't works. Could you give more detail?
    Thanks in advance.

    ReplyDelete
  2. Can you please provide the details about your test scenario and the error stack you got?

    ReplyDelete
  3. The line
    com.jniwrapper.win32.ie.Browser browser = ie.getBrowser().getPeer();
    gives me error because not exists method getBrowser(), so i have created the method in WebSpec.java, then gives me error because not exists method getPeer, so the first line I have used is
    com.jniwrapper.win32.ie.Browser browser = ((IEBrowser)ie.getBrowser()).getPeer();

    With the HtmlDialogListener, i changed the new MyHtmlDialogListener() with new HtmlDialogListener()
    browser.setHtmlDialogListener(new HtmlDialogListener(){
    public void show(HtmlDialogEvent event){
    HTMLDialog myDialog = event.getDialog();
    HTMLDocument dialogDocument = myDialog.getDocument();
    //perform your steps in the modal dailog document here
    }
    });

    The problem is that when click to open de modal window the listener doesn't works. Nothing ocurrs.

    The popup is opened with showModalDialog javascript method.

    Thanks for your help.

    ReplyDelete
  4. Thw line
    com.jniwrapper.win32.ie.Browser browser = spec.getBrowser().getPeer();
    give me compilation roblems and i use
    com.jniwrapper.win32.ie.Browser browser = ((IEBrowser)ie.getBrowser()).getPeer();

    The listener is
    browser.setHtmlDialogListener(new HtmlDialogListener(){
    public void show(HtmlDialogEvent event){
    HTMLDialog myDialog = event.getDialog();
    HTMLDocument dialogDocument = myDialog.getDocument();
    System.err.println("in the listener"); }
    });

    The problem is that nothing ocurrs. It seems the listener doesn't work.

    I open de modal window with showModalDialog javascript method.

    Thanks for your help.

    ReplyDelete
  5. I thought this was being released in Webspec and hence didn't mention it earlier.

    You need to enhance Browser implementation class(IE or Mozilla or Safari) to support getPeer() method. This is well supported in Watij latest version. You can copy the implementation from there. Similar thing you need to do with Listener implementation.

    If you are not very much particular about WebSpec,use Watij, the above steps should work properly.

    ReplyDelete
  6. ok. I'll try with watij. Thank you very much.

    ReplyDelete
  7. I've tried but the thread is hung in method webBrowser.waitReady(timeMillis);
    and that method is in library jexplorer, and i can't see the code.

    ReplyDelete
  8. hi,

    finally works with your code without the line waitUntilReady();
    I don't know why it remains waiting...

    thank you very much.

    ReplyDelete
  9. Regarding waitUntilReady()-> This is because of the browser not returning the status as done after the event. Replace the statement with some definite wait time as 500ms or so to allow some buffer time for page to load.

    ReplyDelete