Robocop is a Java-based testing framework which is an extension of the Android Robotium test tool with features needed to perform automation on Firefox for Android builds.
mobile/android/base/tests
.test<Feature_to_be_tested>.java.in
.hg pull -u
sudo su
) and make sure the PATH variable is updated with the Android SDK location:make -f client.mk
test
followed by the test name and with the extension java.in
(for example, testBookmarks.java.in
).hg qnew <patch_name>
hg add mobile/android/base/tests/<test_file_complete_name>
robocop.ini
from mobile/android/base/tests
and add after the last Robocop test a new line with the test name between sqare brackets ( "[" and "]").hg qpop
#filter substitution package @ANDROID_PACKAGE_NAME@.tests; import @ANDROID_PACKAGE_NAME@.*; /* Insert info about the test here - a basic description of what the test does */ public class test<Feature_to_be_tested> extends BaseTest { @Override // This method is needed in the BaseTest class protected int getTestType() { return TEST_MOCHITEST; // Test type should remain Mochitest } /* * This is the class constructor * This method will contain the test that will be run */ public void test<Feature_to_be_tested>() { } }
protected void setUp()
- Starts Fennec and sets up commonly used member variables. This is usually very similar for every test class.public void test[YourFeature]()
- Your test code goes here. Use the Robocop API to access Fennec elements, click, send keys, and assert conditions.public void tearDown()
- Clean up.BaseTest
then you will not need to add the methods setUp()
and tearDown()
as they are already defined in BaseTest.
tearDown()
method can be overwritten, but make sure to call super.tearDown()
as needed in the method. The same is true for setUp()
.Robotium itself provides a rich API through the Solo
class - javadocs for Solo
are available at [1].
Robocop provides an additional API to make common tasks easier. The main interfaces are Actions
, Element
, and Driver
.
Actions
provides commonly used non-element-specific actions that can be taken on the application, such as dragging and sending key events.
// Actions //This will cause this process to spin until Gecko fires a specific JSON event, such as DOMContentLoaded void waitForGeckoEvent(String geckoEvent); //Clicks the given Key (Actions.SpecialKey.[DOWN|UP|LEFT|RIGHT|ENTER]) void sendSpecialKey(SpecialKey button) //Sends a string of characters to the system. (Most have been implemented but not all) void sendKeys(String keysToSend); //Sends a drag action across the screen void drag(int startingX, int endingX, int startingY, int endingY) // Run a SQL query on the specified database public Cursor querySql(String dbPath, String sql);
Element
represents each of the available UI objects in Fennec including the Awesomebar, the tabs button, and different lists and menus.
// Element //To click the element void click() //Returns true if the element is currently displayed boolean isDisplayed(); //Returns the text currently displayed on the element, or direct sub-elements String getText();
Driver
finds elements and provides info about the UI.
// Driver //This is used to find elements given their id's name Element findElement(String name); //This is used for getting information on scrolls. NOTE: It must be used for the next three methods to return useful information void setupScrollHandling(); int getPageHeight(); //The total height of the page int getScrollHeight(); //How far down the screen the client has scrolled int getHeight(); //The height of the client's view //The following are used to give information on the graphical location of the Gecko view on the screen int getGeckoTop(); int getGeckoLeft(); int getGeckoHeight(); int getGeckoWidth();
Finally, an evolving set of test base classes - BaseTest
, PixelTest
, etc. - can be leveraged for some types of tests.
The following is a list of IDs that can be used with Driver.findElement()
. Most of the following IDs have not been tested, so you might have unexpected results, or require increased APIs for them. To know how a given object is used, in mobile/android/base
, grep R.id.[id-name] *
(from Objdir/mobile/android/base/R.java#id
)
abouthome_content add_tab addons address_bar agent_mode all_pages_list awesome_bar awesome_screen awesomebar_button awesomebar_tabs awesomebar_text background bookmark bookmark_icon bookmark_title bookmark_url bookmarks_list browser_toolbar close container doorhanger_choices doorhanger_container doorhanger_title favicon forward gecko_layout grid history_list info list main_layout notification_image notification_progressbar notification_text notification_title outline plugin_container preferences quit recommended_addon_list reload save_as_pdf screenshot select_list share site_security stop tabs tabs_count title url
String url = "<insert_link_here>"; loadUrl(url);
String url = getAbsoluteUrl("/robocop/robocop_blank_01.html"); loadUrl(url);
BaseTest.java.in
called verifyPageTitle(String title)
but the core code to verify the title is:Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar_title"); // search the awesomebar title mAsserter.isnot(awesomebar, null, "Got the awesomebar"); // log "Got the awesomebar" in the logs assertMatches(awesomebar.getText(), "<insert_title_here", "page title match"); // do a match between expected and actual title
BaseTest.java.in
called selectMenuItem(String item)
but the core code for opening the menu is:mActions.sendSpecialKey(Actions.SpecialKey.MENU); //Open the More menu for devices with old style menus if (mSolo.waitForText("^More$")) { mSolo.clickOnText("^More$"); }
mActions.sendSpecialKey(Actions.SpecialKey.BACK);
addTab(String url)
method from BaseTest.java.in
:Actions.EventExpecter tabEventExpecter = mActions.expectGeckoEvent("Tab:Added"); // Look for a new tab event Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded"); // Look for page load complete
tabEventExpecter.blockForEvent(); contentEventExpecter.blockForEvent();
blockForGeckoReady();
private ListView openBookmarksList() { Activity awesomeBarActivity = clickOnAwesomeBar(); // Click the "Bookmarks" tab to switch to bookmarks list mSolo.clickOnText("Bookmarks"); TabHost tabHost = (TabHost)mSolo.getView(TabHost.class, 0); return (ListView)tabHost.getCurrentView(); }
View child = list.getChildAt(<nr>); //bookmark nr- numbering starts at 0 mSolo.clickLongOnView(child); //long tap to open context menu
expectedTabCount = <nr_of_expected_tabs>; tabCountText = tabCount.getText(); tabCountInt = Integer.parseInt(tabCountText); mAsserter.is(tabCountInt, expectedTabCount, "Number of tabs increased");
Assert
class can be found in the source folder in the subfolder /obj-android/build/mobile/robocop.
Assert
methods for more info about how they work.Assert
will determine if a test fails or passes.public void isnot(Object a, Object b, String name)
Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar_title"); mAsserter.isnot(awesomebar, null, "Got the awesomebar"); // Checks that the awesomebar title is not null and posts in the logs
public void is(Object a, Object b, String name)
ListView list = getAllPagesList(url); mSolo.waitForText(url); mAsserter.is(list.getChildCount(), 5, "all pages list has 5 children (the default bookmarks)"); // Checks that there are 5 entries in the list and posts in the logs
public void dumpLog(String message) // writes text in the logs
public void ok(boolean condition, String name, String diag)
ListView list = getAllPagesList(url); mSolo.waitForText(url); mAsserter.ok(list != null, "checking that all pages list exists", list.toString()); // tests if the list is null and // if it isn't it prints the list // after printing the message of // what the test does
It is not always necessary to rebuild Fennec to use new tests. If you are updating the build with your own test, ensure that your test has been added to the manifest in /PATH/TO/FENNEC/SOURCE/mobile/android/base/tests/robocop.ini
.
Otherwise, you can retrieve tests from the repository by executing:
hg pull hg update
Now you can build the Robocop part of Fennec by executing:
cd objdir sudo make -C build/mobile/robocop/ sudo make package