Selenium-Flex-Tests with Maven +
I wanted to integrate our Flex application with tests into our Maven build. A few days ago I moved the app to Flex 3 and changed the Maven Plugin from the Maven2 Flex Plugin to Flex-mojos. Now the artifacts are in the repository and you don’t need to install the Flex SDK to build the application.
We have written the application as a demo in the first place and now wanting to test it in the wild. Because we use Cairngorm the application is well structured and contains as view layer only minimal parts of logic. Yes, we could include unit tests, but integration tests are far more interesting (from my point of view). In a large code base it could happen, that because of refactoring some things are broken. No deal, if you have tests and a CI system. But in the Flex app there are just tiny parts which I could test in a normal unit test.
Okay, so it should be integration test. Sounds good and not too complicated. There should exist a lot of frameworks because a lot of people start to use BlazeDS and other stuff in Java environments. Just something to start the app, run some tests and get the result back in the CI system.
I started to search on google and was surprised. Most of the blog posts I have found on that topic are just two month old. And there are not so many posts about that topic. With the combination of those posts I figured out, how to solve that problem. What problem?
- Integration tests of our Flex app
- Integrated in Maven
- Should work together with Cairngorm (would be more complicated with some unit tests frameworks)
- Could be Selenium (to start the app and run tests)
- Should be integrated in our continuous integration server TeamCity
- Could be written in Java
First thanks to the blog post of Julia at Blackpepper. She opened my eyes how to work with Java and Flex in combination. It is the combination of the SeleniumFlexAPI, which integrates as Flex to Javascript bridge in your Flex application and FlashSelenium.
SeleniumFlexApi is in one part a Flex library which needs to be included in your app and on the other part an extension to the Selenium IDE. I like the Flex part, because it makes it easy to dive over Javascript into the details of your Flex app. What I don’t really like is the Javascript extension. Yes, it is not only a Selenium IDE part and you can include it into the start of the Selenium Server, but it is far away from Java and Maven.
FlashSelenium is a piece of code which let’s you talk from Java over Selenium with your Flex app. The Java part is very handy, but you need to code into Flex, which methods you could call over your bridge. So I need to write special code, which opens the bridge. The SeleniumFlexAPI is much better in this part.
I liked the solution of the blog post and started to implement it.
First the pom.xml where you need to include the SeleniumFlexAPI (the scope cost me some time):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>agimatec</groupId>
<artifactId>assessor</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>agimatec</groupId>
<artifactId>assessor-flexapp</artifactId>
<packaging>swf</packaging>
<version>${agimatec-assessor-version}</version>
<name>Assessor Flex Application</name>
<url>http://www.agimatec.de</url>
<dependencies>
<!--Flex SDK dependencies-->
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>playerglobal</artifactId>
<version>3.0.0.477</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>flex</artifactId>
<version>3.0.0.477</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>framework</artifactId>
<version>3.0.0.477</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>framework</artifactId>
<version>3.0.0.477</version>
<type>resource-bundle</type>
<classifier>en_US</classifier>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>rpc</artifactId>
<version>3.0.0.477</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>rpc</artifactId>
<version>3.0.0.477</version>
<type>resource-bundle</type>
<classifier>en_US</classifier>
</dependency>
<dependency>
<groupId>com.adobe.flex.sdk</groupId>
<artifactId>utilities</artifactId>
<version>3.0.0.477</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>com.adobe.cairngorm</groupId>
<artifactId>cairngorm-bin</artifactId>
<version>2.2.1</version>
<type>swc</type>
</dependency>
<dependency>
<groupId>org.openqa.selenium</groupId>
<artifactId>flex-api</artifactId>
<version>0.22</version>
<type>swc</type>
<scope>internal</scope>
</dependency>
<!--FlexUnit dependencies-->
<dependency>
<groupId>flexunit</groupId>
<artifactId>flexunit</artifactId>
<version>0.85</version>
<type>swc</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>flexunit.junit</groupId>
<artifactId>flexunit-optional</artifactId>
<version>0.85</version>
<type>swc</type>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/flex</sourceDirectory>
<plugins>
<plugin>
<groupId>info.rvin.mojo</groupId>
<artifactId>flex-compiler-mojo</artifactId>
<extensions>true</extensions>
<configuration>
<includeSources>
<param>${project.build.sourceDirectory}</param>
</includeSources>
<locales>
<param>en_US</param>
<param>de_DE</param>
</locales>
<debug>true</debug>
</configuration>
</plugin>
<plugin>
<groupId>info.rvin.mojo</groupId>
<artifactId>asdoc</artifactId>
</plugin>
</plugins>
</build>
</project>
To get the Flex application compile with Maven you need to download the SeleniumFlexAPI and include the swc-file into your Maven repository, because it is (not yet) available on public repositories.
After compiling you can start the Selenium IDE and load the extension or go directly to FireBug and try to call the methods. Be aware, that the args-parameter is normally optional, but needs to be filled for the Javascript-Flex bridge (also cost me some time).
To call a method of your running application in Firefox fire up in FireBug’s console:
window.document['AppName'].getFlexExists('NameOfAnElement','');
To test your application you need to know, what the name of your application is (can be found in the HTML calling the Flash file) and you need to give ids to your elements, because there is just an id locator at the moment.
If you are at this point we can now switch to the Java part with Selenium. Selenium is just Javascript when you are in the browser. So all you do is to call the Javascript function which you called before over Firebug. FlashSelenium is a good wrapper for that call which means that you don’t have to write normal strings into your Selenium commands. I like a little bit more comfort and wanted to wrap the SeleniumFlexAPI a little bit closer. Also there are some methods in the FlashSelenium you don’t need with this solution. So I started to implement my own little wrapper. Maybe it is also interesting for the SeleniumFlexAPI (if completed with all methods).
Here is the beginning of the code:
package com.agimatec.assessor.selenium;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
public class FlexSelenium {
Selenium selenium;
String flexApp;
public FlexSelenium(String ip, int port, String browser, String url, String flexApp) {
selenium = new DefaultSelenium(ip, port, browser, url);
this.flexApp = flexApp;
}
public void start() {
selenium.start();
}
public void open(String url) {
selenium.open(url);
}
public void stop() {
selenium.stop();
}
public String doFlexClick(String id) {
return callFlexBridge("doFlexClick",id);
}
public boolean getFlexExists(String id) {
return callFlexBridge("getFlexExists",id).equals("true");
}
private String callFlexBridge(String method, String id) {
return callFlexBridge(method, id, null);
}
private String callFlexBridge(String method, String id, String args) {
if(args == null || args.trim().equals("")) {
args = "''";
}
return selenium.getEval("window.document['"+flexApp+"']."+method+"('"+id+"',"+args+");");
}
}
And now the test case is the only thing which is missing. I used TestNG because it can be easier configured in a Selenium environment (when it started to become more complicated with several browsers, plattforms, test suites, test groups …):
package com.agimatec.assessor.selenium;
import org.testng.annotations.Test;
public class AssessorTest {
private final static String URL = "http://192.168.1.175:8080/assessor-webapp";
FlexSelenium selenium;
@Test
public void setUp() throws InterruptedException {
selenium = new FlexSelenium("192.168.1.254", 4444, "*firefox", URL, "Terminal");
selenium.start();
selenium.open(URL);
while(!selenium.getFlexExists("videoPlayer")) {
Thread.sleep(1000);
}
selenium.doFlexClick("videoPlayer");
Thread.sleep(300);
selenium.doFlexClick("enterUserModeButton");
selenium.stop();
}
}
[...] I used TestNG because it can be easier configured in a Selenium environment (when it started to become more complicated with several browsers, plattforms, test suites, test groups …): package com.agimatec.assessor.selenium; … Original post [...]
I did the following to ensure flash had been properly loaded and started before test executes:
public void testFooBar() {
waitForFlashLoaded();
assertEquals("hello world", flashApp.call("callMe"));
}
private void waitForFlashLoaded() {
try {
while (flashApp.PercentLoaded() != 100) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
// craps
}
}
Yes, that is a much nicer solution for the start of the Flex app. Do you have a lot of test running with Flex and Selenium?
What is your experience? Is it stable?
We are just at the beginning of our Flex tests.
Cheers
Simon
Sorry, but I am at the beginning of flex testing too.
[...] Selenium-Flex-Tests with Maven Flex acceptance testing and continuous integration [...]
I just want to make sure:
Does this solution requires opening ExternalInterface from the swf that is the subject of testing?
Hi, This test is exactly what I’m looking for. The app has all the components I need to test. So thanks in advance..but I can’t seem to find the source code for the tests and the app itself on source forge could you give a link directly to them?
I’m surprised that we have to actually write code to get integration tests to work. I would have expected there to be recording of mouse interactions with Flash to be enabled.