Table of Contents

Testing Adobe Flash with Selenium

Flash files are the animated and/or interactive content for web pages. These types of content is primarily created by Flash development environment. However some available addins let you create Flash content on Ecllipse and similar development environments.

Problem Statement

Flash files are closed files and are rendered in a container on a webpage. For ex Flash player on Mozilla and chrome and on ActiveX control in IE. The containers are embedded in <object/> or <embed/> tags in an HTML. So when you open a web page containing a Flash file browser first loads the Player (Flash or ActiveX) and then load the file into it to display the content. The flash object model is not accessible using any HTML element.

So how do we test Flash content using Selenium?

The straightforward answer to it is that Selenium has no interface to interact with your Flash content. Flash files are programmed in ActionScript and are very similar to JavaScript. Flash files also contain programming Elements just like other languages. For e.g. they too have buttons, text box, etc. Interacting with these elements cause the Flash file to call some internal methods to do the task. For eg, a button on flash content may cause the background color of flash content to change. To the rescue comes ActionScript, it exposes a class called ExternalInterface to the developers. This class is particularly important if you want to expose the internal methods of a Flash file to the outside world. The outside world is the Browser or any programming control that is hosting the content. So if we expose our internal methods from Flash file to the Browser then we can call them directly using JavaScript. Here the use of Selenium comes, it lets you execute and Inject JavaScripts on a webpage.

When to automate Flash content testing?

As of now, it's better to do a solid Return of investment calculations for automating Flash content. The reason is that a tester will have to code lots of functions inside the Flash program and expose them to be called by the browser. If your ROI turns out to be beneficial go ahead and code it. So the next question that comes to mind is

How do we expose methods in Flash?

Its a fairly simple process. All you have to do is use the ExternalInterface class. We will start it with a small example. This is a small flash application which contains 3 buttons. Add, Subtract and Multiply. These three buttons when clicked sends a text to a Text control and write down what the name of the button is. So if you click Add you will find text "Add" being added to the Text control.

To view sample application, click here.

Now the task is how do we do it programmatically from Selenium. This is how a simple Flash file looks like.

package

{

import flash.display.Sprite;

import flash.events.*;

import flash.external.ExternalInterface;

import flash.text.TextField;

import flash.utils.Timer;

import flash.text.TextFieldType;

import flash.text.TextFieldAutoSize;

import flash.system.Security;

public class SimpleCalculation extends Sprite

{

private var outputNumber:TextField;

private var AddByOne:Sprite;

private var SubtractFive:Sprite;

private var MultiplyTwo:Sprite;

public function SimpleCalculation()

{

/*

This line allows the ActionScrit object to communicate between domains.

If this is not used we cannot call functions from browser

*/

Security.allowDomain("*");

//Creating the text field

outputNumber = new TextField();

outputNumber.width = 450;

outputNumber.height = 325;

outputNumber.multiline = true;

outputNumber.wordWrap = true;

outputNumber.border = true;

outputNumber.text = "0"

addChild(outputNumber);

//creating button object

AddByOne = new Sprite();

AddByOne.mouseEnabled = true;

AddByOne.x = outputNumber.width + 10;

AddByOne.graphics.beginFill(0xcccccc);

AddByOne.graphics.drawRoundRect(0, 0, 80, 18, 10, 10);

AddByOne.graphics.endFill();

AddByOne.addEventListener(MouseEvent.CLICK, addNumberCallFromBrowser);

addChild(AddByOne);

SubtractFive = new Sprite();

SubtractFive.mouseEnabled = true;

SubtractFive.x = outputNumber.width + 10;

SubtractFive.graphics.beginFill(0xcccccc);

SubtractFive.graphics.drawRoundRect(0, 20, 80, 18, 10, 10);

SubtractFive.graphics.endFill();

SubtractFive.addEventListener(MouseEvent.CLICK, substractNumberCallFromBrowser);

addChild(SubtractFive);

MultiplyTwo = new Sprite();

MultiplyTwo.mouseEnabled = true;

MultiplyTwo.x = outputNumber.width + 10;

MultiplyTwo.graphics.beginFill(0xcccccc);

MultiplyTwo.graphics.drawRoundRect(0, 40, 80, 18, 10, 10);

MultiplyTwo.graphics.endFill();

MultiplyTwo.addEventListener(MouseEvent.CLICK, multiplyNumberCallFromBrowser);

addChild(MultiplyTwo);

outputNumber.text = "Completed loading \n";

initApp();

}

private function addNumberCallFromBrowser(event:MouseEvent):void

{

Add();

}

private function multiplyNumberCallFromBrowser(event:MouseEvent):void

{

Multiply();

}

public function substractNumberCallFromBrowser(event:MouseEvent):void

{

Subtract();

}

/*

The primary purpose of this function

is to initialize the external interface calls.

External interface calls fail if Javascript is not ready

on the page when we make the call. This causes a faliure when

JavaScripts makes a call to the expected functions

NOTE: this function will try for 5 seconds to get the JavaScript ready

notification

*/

private function initApp():void

{

var counter:Number = 0;

if(ExternalInterface.available)

{

while(counter < 300)

{

if(isJavaScripLoaded())

{

outputNumber.appendText("Java script loaded \n");

ExternalInterface.addCallback("Multiply" , Multiply);

ExternalInterface.addCallback("Subtract" , Subtract);

ExternalInterface.addCallback("Add" , Add);

counter= 399;

}

else

{

outputNumber.appendText("Javascript not ready yet \n");

}

counter = counter + 1;

outputNumber.appendText("Javascript not ready yet! trying again " + String(counter) + "\n");

}

}

}

private function isJavaScripLoaded():Boolean

{

var sa:Boolean = ExternalInterface.call("isJavaScriptReady");

return sa;

}

private function Add():void

{

outputNumber.appendText("Add was called \n");

}

private function Subtract():void

{

outputNumber.appendText("Subtract was called \n");

}

private function Multiply():void

{

outputNumber.appendText("Multiply was called \n");

}

}

}

The above code is in ActionScript which is pretty much close to java script. Instead of going deep into the gory details of ActionScript and how this code is structured, let's just see the important part here This is a simple Flash file which has three  buttons defined by

  • AddByOne

  • SubtractFive

  • MultiplyTwo

and a text box

  • outputNumber

Let's see what AddByOne does. When someone clicks on this button when is displayed on the browser, addNumberCallFromBrowser() method is called. This method is hooked to the OnClick mouse event. This means whenever someone click on this element addNumberCallFromBrowser() will be executed. Now go to the code section of this method and you will notice that it in turn calls the  Add() method.  Add() method does the printing of text in the text box control, as you can see. Similarly all the three buttons have corresponding function, as shown in the code. Now if we were to test this application we would be interested in clicking on any of the three buttons using Selenium right? Yes that right, also a few more complex scenarios can be built around it, lets just focus on the task of clicking on the buttons. Eventually, by clicking on the buttons we would want to test the Add(), Substract() or may be Multiply() methods? right? So to do that from browser we have to expose these methods to the outside world. The browser in the case and to be specific the JavaScript engine running inside the instance of browser hosting it. This is done inside the initApp() method. You can see that we have

ExternalInterface.addCallback("Multiply" , Multiply);

ExternalInterface.addCallback("Subtract" , Subtract);

ExternalInterface.addCallback("Add" , Add);

This will enable us to call this method directly from JavaScript. Here is the page hosting this Flash file which you can use to run  your selenium code.

Now the selenium part

As discussed above we have just exposed our methods (Multiply, add and Subtract) to the browser. How do we call these methods?

Simple, by injecting java script using selenium. I hope you guys are familiar with Selenium usage and can easily understand this part. Else try to start up with tutorials on our site, here

Click on view source of the test app page and you will find that .Swf file is hosted using the id:SimpleCalculation

We know that SimpleCalulation object has exposed Add() method. So a javascript like this would do the trick and call the Add() method

"document.getElementById('SimpleCalculation').Add()"

Complete selenium code on C# would look like this

InternetExplorerDriver ie = new InternetExplorerDriver(options);

ie.Navigate().GoToUrl(@"https://googledrive.com/host/0B3SaC4MIQsEEZkwwcDhHaVQ4OFk/calc.html");

ie.ExecuteScript("document.getElementById('SimpleCalculation').Add()");

ie.ExecuteScript("document.getElementById('SimpleCalculation').Multiply()");

ie.ExecuteScript("document.getElementById('SimpleCalculation').Subtract()");

ie.ExecuteScript("CallAdd()"); //Look at the page html source to understand this and following methods

ie.ExecuteScript("CallMultiply()");

ie.ExecuteScript("CallSubtract()");

WebDriverManager: How to manage browser drivers easily?
WebDriverManager: How to manage browser drivers easily?
Previous Article
Custom Firefox Profile for Selenium
Custom Firefox Profile for Selenium
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback