From The Document Foundation Wiki
Jump to: navigation, search

This is the preliminary documentation for the UI testing framework with a special focus on the python side.


The UI testing consists of two parts, a C++ piece that wraps the LibreOffice UI in an introspection library and a Python framework with the actual test code. The connection between the two parts is done through a simple mostly untyped UNO interface.

C++ introspection library

The C++ introspection library consists of an UNO API that us used for the communication with the python part of the framework and wrappers for many UI objects. The UNO interface only has a few method and most of the communcation happens through string parameters.

The wrapper around the UI objects provides about the same methods as the UNO interface plus some helper methods.

Python framework

Writing tests

Makefile part

A simple makefile for the UI testing looks like the calc demo makefile. The important part is to use the UITest gbuild class and let the gb_UITest_add_module point to the directories with test files.

Normally nothing more is required and most is handled in the gbuild UITest class.

$(eval $(call gb_UITest_UITest,range_name))

$(eval $(call gb_UITest_add_modules,range_name,$(SRCDIR)/sc/qa/uitest,\
    test_dir1/ \
    test_dir2/ \

The range_name parameter is the name of the test target. The $(SRCDIR/sc/qa/uitest is the base directory and the parameters in that part lists the directories to search for tests.

Optionally the test can be run with a specific registrymodifications.xcu file to support running with specific configuration settings. Each test has an own user profile in workdir/UITest/test_name/user/. With the following makefile snippet a file can be copied into that directory.

$(eval $(call gb_UITest_use_configuration,range_name,$(SRCDIR)/sc/qa/uitest/range_name/registrymodifications.xcu))

This would copy the file sc/qa/uitest/range_name/registrymodifications.xcu to the user profile and the test would run with these settings.

Writing the Python code


Commands available on UI elements


Handling the State of UI objects

The method to get the state of the UI object is provided by all UI elements. The method returns the state as a sequence of PropertyValue.


The UI testing framework provides a method to convert the returned sequence of PropertyValue to a python dictionary.

from uitest.uihelper.common import get_state_as_dict


Sending keyboard input to an element

from uitest.uihelper.common import type_text

xWriterDoc = self.xUITest.getTopFocusWindow()
type_text(xWriterEdit, "Test")

Selecting a tab in a dialog

from uitest.uihelper.common import select_pmacOSDialog = self.xUITest.getTopFocusWindow()
xTabs = xDialog.getChild("tabcontrol")
select_pos(xTabs, "0")

Selecting text

from uitest.uihelper.common import select_text

xEdit = xAddNameDlg.getChild("edit")
select_text(xEdit, from_pos="2", to="12")

Setting Zoom

xWriterEdit = xWriterDoc.getChild("writer_edit")

xWriterEdit.executeAction("SET", mkPropertyValues({"ZOOM": "200"}))

GOTO page

xWriterEdit = xWriterDoc.getChild("writer_edit")

xWriterEdit.executeAction("GOTO", mkPropertyValues({"PAGE": "1"}))

Control Actions

Control Code Assert
xControl.executeAction("CLICK", tuple())


from uitest.uihelper.common import type_pos

type_text(xControl, "Text")
self.assertEqual(get_state_as_dict(xTitleText)["Text"], "Text")
xControl.executeAction("CLICK", tuple())
self.assertEqual(get_state_as_dict(xControl)["Selected"], "true")
Charmap Widget
from import mkPropertyValues

xControl.executeAction("SELECT", mkPropertyValues({"COLUMN": "2", "ROW": "2"}))


# Unfold/Fold the tree
xTreelist = xExDBDlg.getChild("availablelb")         
xTreeEntry = xTreelist.getChild('0')
xTreeEntry.executeAction("EXPAND", tuple())  #Available Databases
xTreeEntry.executeAction("COLLAPSE", tuple()) #Click on the Bibliography

xTreeEntry2 = xTreeEntry.getChild('0')
xTreeEntry2.executeAction("SELECT", tuple())


from uitest.uihelper.common import select_pos

select_pos(xCombobox, "1")
self.assertEqual(get_state_as_dict(xNumbering)["SelectEntryText"], "List 1")
ListBox ( by position)
from uitest.uihelper.common import select_pos

select_pos(xListBox, "1")
self.assertEqual(get_state_as_dict(xListBox)["SelectEntryText"], "List 1")
ListBox ( by name )
from uitest.uihelper.common import select_pos

        categoryLB = xCellsDlg.getChild("categorylb")
        props = {"TEXT": "Time"}

        actionProps = mkPropertyValues(props)
        categoryLB.executeAction("SELECT", actionProps)
self.assertEqual(get_state_as_dict(categoryLB)["SelectEntryText"], "Time")
from uitest.uihelper.common import select_pmacOSTabs = xFunctionDlg.getChild("tabs")
        select_pos(xTabs, "1")


Tabdialog (by position)
from uitest.uihelper.common import select_pmacOSTabs = xFunctionDlg.getChild("tabs")
        select_pos(xTabs, "1")


Tabdialog (by name)
        props = {"NAME": "Borders"}
        propsUNO = mkPropertyValues(props)
        xCellsDlg.executeAction("SELECT", propsUNO)


xDecimalPlaces.executeAction("UP", tuple())
xDecimalPlaces.executeAction("DOWN", tuple())
self.assertEqual(get_state_as_dict(xDecimalPlaces)["Text"], "Title text")
xSuperscript.executeAction("CLICK", tuple())
self.assertEqual(get_state_as_dict(xSuperscript)["Checked"], "true")

Keyword Actions


from import mkPropertyValues

ui_object.executeAction("TYPE", mkPropertyValues({"KEYCODE":"CTRL+A"}))


  • "ESC"
  • "TAB"
  • "DOWN"
  • "UP"
  • "LEFT"
  • "RIGHT"
  • "DELETE"
  • "INSERT"
  • "RETURN"
  • "HOME"
  • "END"
  • "PAGEUP"
  • "CTRL"
  • "ALT"
  • "SHIFT"

How to extend the introspection library

UI elements extending vcl::Window

Other UI elements

Tools for writing a test

The difficult part about writing a test is to figure out which UNO commands to send and which action to call on an UI object. Currently there is some work going on to support logging what you do in a log file that will contain these information. The logging of UNO commands is already available in master.

To enable the logging you need to set LO_COLLECT_UIINFO to a file name that will be used to write the log. The file will be placed into the uitest directory inside of the user profile.

1. Launch LibreOffice like

LO_COLLECT_UIINFO="test.log" instdir/program/soffice

2. Simulate what you want to in the uitest with the mouse

3. Close LibreOffice

4. Open the resulting file in instdir/uitest/test.log

Running the test

Before we push the test to master we should obviously check that the test is working. A simple way is to execute all UI tests in the uitest module through make uitest.uicheck. However we would like to see the UI while the test is being executed and the tests are run headless by default.

The solution that I currently use is a simple script starting a test. Obviously the plan is to have a better solution in the framework at some point.

You might also need these environment variables to make it work

export PYTHONPATH=/home/xisco/libreoffice/instdir/program/
export URE_BOOTSTRAP=file:///home/xisco/libreoffice/instdir/program/fundamentalrc

When you execute the test with the visible UI you’ll notice that the test is too fast to see what is going on. A quick and dirty solution is to add python’s time.sleep which stops execution for a bit. The other solution that you can actually leave in the code (only leave a few useful ones in a test) in interesting places is uitest.debug.sleep. This method is ignored unless the test is started in debug mode by passing the --debug parameter to the test.

When you need to run only one test in test script file, run following command:


for example

UITEST_TEST_NAME="sorting.CalcSorting.test_Sortingbuttons_detect_columnheaders" ./

Unsupported ui items

  • background color selector - Calc/Format cell
  • file properties- custom properties
  • insert -> Fontwork
  • Hyperlink dialog. Insert ->Hyperlink
  • File -wizards
  • Calc - Input line
  • writer and calc's comments

List of UI tests in master

You can check the list of already implemented UItests here

More Information