Saturday, December 22, 2007

FormItem problem

Hi!

I just recently got a notice on my last post from Neil that when using FunFX a null pointer exception is thrown when any form item's label in a form is null as shown in the first listing. Neil pointed out that it was also happening when the label was set to an empty string.

<mx:form>
<mx:formitem label="Form Label">
<mx:label id="lLabel"/>
</mx:formitem>
<mx:formitem>
<mx:textinput id="tTextInput"/>
</mx:formitem>
</mx:form>


Neil pointed out that it was something to do with the FunFX and FormItemAutomationImpl interaction. And that one need to set all the form items labels to a non empty string. And that using whitespaces as label affects the layout. He suggested a nice workaround until a fix with the FormItemAutomationImpl is done. And that is to set the label width to 0.

<mx:form>
<mx:formitem label="Form Label">
<mx:label id="lLabel"/>
</mx:formitem>
<mx:formitem label="" labelWidth="0">
<mx:textinput id="tTextInput"/>
</mx:formitem>
</mx:form>


I have created the error for my own, and the reason for the error is as Neil said. The FunFX uses the automation framework from Adobe to create string id of the display objects that it interacts with. And this method in the FormItemAutomationImpl.as as displayed in the following listing. When the label of the formitem is null, there is no check that will prevent the method to call the length method of the label, which might be null.

private function getItemAutomationName(child:IAutomationObject):String
{
//Have cut down the method
result = (label.length != 0 ? label + ":" + child.automationName : child.automationName);
// More in the real method
}

I have not yet been able to check wether it is possible to just add a null pointyer check in the method. But this will probably implie a change in th corresponding method that creates an object from the string id.

I hope this will help people in the same situation as Neil. And I will see if it can be fixed. But so long you will need to do as Neil suggested and set the labelWidth of the form item to zero.

Thanks alot Neil, for this valuable tip and solution!

Tuesday, December 4, 2007

Some problems and solutions when using FunFX

Hi everyone.

These past days I have used some time trying to set up FunFX for the project I am on at work. I have said to my self earlier (because some people have had some problems with custom components) that I would write a post about this. Because I do no know to much about this area, how FunXF actually handles, I have not had the time to do this yet, but I asure you that it will come.

So instead I will use this post to talk about some of the problems and solutions I have had the last few days.

First of all double clicking a row in a datagrid made me a bit frustrated today, because it would not replay the action that I wanted to do. The following line was what I tried to do (the datagrid contained a row with a column that held the value "Person".

@ie.data_grid("name").double_click(:item_renderer => "Person")

After some error checking it seems that you must select the row before doing a double click. The following lines works perfect. I have not yet found a good reason why this behavior or a better solution if people think it should be handled better.

@ie.data_grid("name").select(:item_renderer => "Person")
@ie.data_grid("name").double_click(:item_renderer => "Person")


Anther thing I has some trouble with was accessing elements of an repeater when there is an hierarchy of display objects within the repeater, then the number of the single element I wanted waas multiplied with the number of parents abow. In the following example I would get 4 tLabels and 4 tData.

<mx:repeater id="rep" dataprovider="{}">
<mx:vbox id="vboxen">
<mx:hbox id="hboxen">
<mx:textinput id="tLabel" text="{rep.currentItem.label}"/>
<mx:textinput id="tData" text="{rep.currentItem.data}"/>
</mx:hbox>
</mx:vbox>
</mx:repeater>

I am still testing the solution (and will probably put out a new version of FunFX in the next days), so I am not completely sure that it is the best solution. But I have up until now used the objects automationChildren when try to reach the children, but this seems to multiply children of repeaters and like. So I have switched to used the rgular children instead, and for now it seems to do the trick, but I still have to test that all other displayobjects still are supported.

With the new solution the issue where you had to write the repeater and then the object you wanted is now gone. Now the repeater will not exist as an display obejct. So you write as the last bulk says.

@ie.repeater("rep").text_area("tLabel")[0].input(:text => "Test") # This is now wrong


@ie.text_area("tLabel")[0].input(:text => "Test") # This is correct


But so far I am able to do automatic functional testing of a registration form and to ensure that the calculation response from this registration is correct. Due to low speed these tests are not run too often, but I will try later to include the tests in the nightly build.

Thursday, November 22, 2007

FunFX - How to write tests

The last post talked about howto get started and how to make the Flex application ready for testing. I am sorry about the time it took me to post this sequel.

FunFX is a framework that is composed of two parts, one adapter (the last post talked about this part) that enables the Flex application to be tested, and one Ruby framework that enables you to drive an Internet Explorer instance with the Flex application.

Some people ask me if there is an easy way to implement support for either FireFox or other browsers, and the answer to this is both yes and no. It depends, there are currently only IE that is implemented and the reason for this is IE's support for COM objects. I will explain this implementation in a bit more detail in another post.

This post will talk about the Ruby framework mentioned in the beginning. This Ruby framework is a Ruby gem. This framework creates an instance of a Internet Explorer window. Then with some initializing methods you will direct the IE window to the address of the Flex application.
This is shown in the follwoing table. The first sentance creates an instance of FunFX. When executing the second line with the start method FunFX creates an instance of IE in the background with the help of Win32OLE. The argument tells FunFX if you want the IE to be visible or not.

@ie = Funfx.instance
@ie.start(true)
@ie.speed = 1
@ie.goto("http://localhost/flexapplication.html", "flexapplication")


The last sentance in the initialization is the method that directs the browser to the Flex application and hooks on to the actual Flex object with the help from Win32OLE, and the name of the swf file. If you have an html file named index.html that contains a swf file that is named flexApp.swf and is located at http://localhost/flexapplication/index.html. The

@ie.goto("http://localhost/flexapplication/index.html", "flexApp")


After this initialization, the @ie variable (which is an instance of FunFX) is ready to interact with the Flex application.

The FunFX in itself does not test Flex applications in the sence of asserts, it just enables you to drive an Flex application programmatically and get the state and text of all display objects. To make assertions and create test scripts you will need to use FunFX together with a testing framework of your choice. A couple of examples are RSpec, and Test::Unit. FunFX together with any of these tools make up an automated functional testing tool.

Before I will show you an example of FunFX together with these tools, I will explain in short how to use FunFX in the sence of driving the Flex application programmatically.

A Flex application is built as an hierarchy of different display objects, with the Application object as the root node. With FunFX you can think of @ie the root node of the Application object.

An example of interacting with a display object is shown in the box below.

@ie.button("buttonName").click

This line of code will click the button with id or label named "buttonName". This button can be located anywhere in the Flex hierarchy. In version 0.0.1 FunFX only supported single elements, and then it stopped when it found a object matching this signature. But this was a problem with repeaters, which creates children with the same id's.

So in 0.0.2 it finds all objects that matches that type and name, and delivers them as an array, as shown below:

@ie.button("buttonName")[0].click

To interact with a display obejct you must provide the label or id.

Some flex event needs arguments as when inserting text into a textbox. This is done as follows:

@ie.text_area("price").input(:text => "This is the new text")


@ie.data_grid("gridName").drag_start(:dragged_item => "Name of item")
@ie.data_grid("gridName").drag_drop


There are many more methods. Unfortunately there are no good overview of all the methods and their arguments. But you should look at the AutomationGenericEnv.xml, which describes all the display object types and their events and arguments.

When testing the functionality of an application it does not help being just able to drive the application. It must be possible to extract some information to assert with a testing tool such as RSpec or Test::Unit.

You can get information about alot of thing, such as visibility, text, rows in a datagrid, enabled etc. These are called properties and are also described in the AutomationGenericEnv.xml.

The following displays some examples of extracting data. It is possible to extract the selected index of an data grid, making it possible to extract information about that grid line with the tabular_data property. This creates a comma separated string containing the row information. If there are images in the row, the name of the images will be displayed.

pos = @ie.data_grid("gridName").selected_index
@ie.data_grid("gridName").tabular_data(:start => pos)

@ie.label("labelName").text
@ie.application("applicationName").current_state

I have not yet tried how this works with the new upgraded grid in Flex 3.

The following is an example test that tests an flex application that adds a product to a datagrid with the use of an popup window. This test is test nr 1 at the bottom of this post.

require 'test/unit'
require 'funfx'

class TestProductOne <>

def setup
@ie = Funfx.instance
@ie.start(true)
@ie.speed = 1
@ie.goto("http://funfx.rubyforge.org/Flex/FlexRepeater.html", "FlexRepeater")
end

def teardown
@ie.unload
end

def test_insert_product

assert_equal(0, @ie.data_grid("dgOffer").num_rows)

add_product("Shirt", "Tennis")
@ie.button("bOk").click

assert_equal(1, @ie.data_grid("dgOffer").num_rows)

end

def add_product(name, category)
@ie.button("bAddProduct").click

@ie.text_area("tName").input(:text => name)
@ie.text_area("tCategory").input(:text => category)
end
end


This post is a bit messy, but i tries to explain some of the basic elements. The following post will try to explain other concepts in more detail.

I have put out an test application that set up for testing with a couple of simple actions to perform at TestApplication. At the following links I have also written a couple of tests that test this application. Please try them out and alter them to see if you get it going (the source code of the view files are available at view source, or this address source-code).
I hope this test application and test scripts help you to get going.

Saturday, November 17, 2007

FunFX - Getting started

At the website for FunFX at Rubyforge, there are some old direction on how to get started with FunFX. I will now make a better up-to-date getting started with FunFX (and hopefully get to update the website).

The first thing you need is to get Flex Builder from Adobe, and the FunFX zip file located at Rubyforge. The FunFX zip file contains three files;
  • AutomationGenericEnv.xml
  • FunFXAdapter.swc
  • FunFX-0.0.x.gem.
To get things to workyou will need additional three files, but they are part of the Flex 3 SDK (with Flex 2 SDK these files are bundled with Flex Data Services and the automation package, but you will be able to get the files from Flex 3 SDK) ;
  • automation_agent_rb.swc
  • automation_agent.swc
  • automation.swc.
The automation_agent_rb.swc must be located in the language folder in use in the locale folder. In the Flex SDK 3 version this file is already in place in the correct folder.

The FunFX gem file must be installed locally on your computer. It does not exist in any public repository yet, so you must choose the local gem file located in the FunFX zip file.

All the other files will be used when creating the Flex project, which I will begin explaining now. I will explain using Eclipse as the IDE.

Creating a new Flex Project
The first thing is to create the Flex project of choice. Then you must add the AutomationGenricEnv.xml to the root path of the project or just add it directly to the bin catalog or the output folder of choice. The adapter uses this file to build the automation environment of all display objects.

To be able to take advantage of the FunFXAdapter file you must add it as a compiler option as shown in the picture below. The adapter is relying on the files automation_agent.swc and the automation.swc files, and thus they must also be added as a compiler option.

I have tried to add these swc files as swc files in the build path but this does not work. I am not really sure why this is, so if anybody has any comments on this fact please let me know.



Now your application is ready to be tested. Remember to be consistent with giving all your display object uniq id's and the testing will be more efficient.

At the end of this post it is an important notice I have to give, and that is about different versions of Flex SDK's. It seems that Flex projects does not like swc files that is compiled with different SDK versions. Due to this the precompiled versions of the FunFXAdapter.s that is supplied with the FunFX zip file might not work with your application (the version out now ,FunFX version 0.0.2 is compiled with Flex SDK version 3.0.0). If this happens download the source code and compile your own version.

I hope this post will help you get started with FunFX, allthough I know I have not talked about how to write the actual tests. The next post will talk about how to write these tests with Ruby.

FunFX - The background

FunFX is a framework for funcional testing of Adobe Flex applications. This post will talk about the background for this tool and some on the implementation decisions.

According to Wikipedia, Adobe Flex is a collection of technologies released by Adobe Systems for the development and deployment of cross platform, rich Internet applications based on the proprietary Adobe Flash platform.

FunFX was initiated by Bekk Consulting in desember 2006 as a master thesis at the Norwegian University of Science and Technology. This was due to Flex's lack of a proper tool for automated functional testing. The only tool was Mercury's Quick Test Professional, which does not support TDD and cost a whole lot of money. We wanted to create an open source version that would support TDD.

I began the work on this framework January 2007, and did not have a lot of experience with Flex. I decided to use Ruby as the language for the actual framework for writing the test scripts.

The first initial problem and the most critical part of this framework was how to be able to talk to the Flex application and make it replay certain events. After some starting tips from Matt Chotin, Sreenivas Ramaswamy, and Matt Horn from Adobe, I decided to use the ExternalInterface API. This enabled me to expose certain "generic" methods out, enabling Ruby scripts to make calls into the Flex application.

I built a Flex library file that acts as an adapter between a Flex application and the Ruby tests. The Ruby framework is dynamically built from an XML file delivered by Adobe that describes all the different display objecs and their events and properties. This makes it possible to write test lines as the following:

@ie.button("name").click
@ie.button("name").label

When running the Ruby script the adapter will try to find a display object by the type button with the name "name" and run either the click event or delivering the lebel text of the button.

The Ruby framework uses the WIN32OLE to drive an Internet Explorer window and the Flex application displayed.

There are currently no support for other browsers or to test a Flex application in the Flash player.

The next post will help getting started with FunFX.

First post

Hi everybody! Aye, caramba, my first blog post ever.

Thought I would begin to tell what kind of topic this blog will have. And it will primarily contain post about my work, I am a computer engineer from Norway. And more specific I will post topics surrounding my little project FunFX that tries to enable automatical functional testing of Flex applications.

But you might even see a post about my regular life also.