moggi's blog about Libreoffice hacking

Writing a LibreOffice Calc UI test


After the blog post describing the design of the UI testing framework I wanted to quickly follow up with a post showing how to write a simple test.

As is a bit expected (in the end I’m still a calc developer 😉 ) currently the support for calc tests is better than for other applications. There is already support for writer, impress and math with different degree of completeness. Especially the special main windows have only a limited support for special operations right now. A future blog post will show how to add introspection support to a special UI element.

In this blog post I will show how to add a simple Calc UI test that creates a range name.


We will start with a new file that contains just the minimal boilerplate code to have a new test that is discovered by the test framework. We place the file in the uitest/calc_tests directory as this one is listed in uitest/ to contain test code.

Inside of any class derived from uitest.framework.TestCase any method with a name starting with test will be executed by the test framework. We will simply name our method for now test_number_format


Writing the test

Let us start with the code and explain on the code what each part does.

1  from import mkPropertyValues
3  from uitest.framework import UITestCase
5  class CreateRangeNameTest(UITestCase):
7      def test_create_range_name(self):
9          self.ui_test.create_doc_in_start_center("calc")
11         self.ui_test.execute_modeless_dialog_through_command(".uno:AddName")
13         xAddNameDlg = self.xUITest.getTopFocusWindow()
14         xEdit = xAddNameDlg.getChild("edit")
16         actionProps = mkPropertyValues({"TEXT":"simpleRangeName"})
17         xEdit.executeAction("TYPE", actionProps)
19         xAddBtn = xAddNameDlg.getChild("add")
20         xAddBtn.executeAction("CLICK", tuple())
22         self.ui_test.close_doc()


Obviously line 1 and 3 just import the method and class that we need.

Line 5 creates a class that inherits from our UITestCase class and therefore all methods in it will be executed as test cases.

Line 7 defines the test method. Note that the method name needs to start with test to be picked up by the test framework.

The test framework starts LibreOffice and opens the start center so line 9 is a helper method that clicks on the Calc button in the start center and waits until the document is ready.

By line 11 we have a working calc document and need to open the range name dialog. There are a few helper methods for this in the UITest class. All dialogs are opened by sending an UNO command ID (in our case “.uno:AddName“) instead of going through the menus. Currently there are two separate methods for modal and modeless dialogs but the plan is to combine the two methods into one. As soon as this method returns the dialog is ready and we can work with the dialog.

Line 13 and 14 select different UI elements. In line 13 we get a reference to the current top window that has the focus. This is the window that represents the whole dialog. From this UI element we ask for the child with the ID “edit”. The ID is imported from the ui file of the dialog. xEdit now contains a reference to the name edit of the dialog.

Line 16 and 17 send a string that should be typed to the edit. mkPropertyValues in line 16 creates the required sequence from a dict. In line 17 we send this sequence as argument to executeAction. The first argument to the method is the action that should be executed on the UI element. For the TYPE action the framework generates keyboard events that are sent to the element.

Line 19 and 20 select the “add” button and send a “CLICK” action closing the dialog. At this point we could add any code we want to assert that the range name has actually been created correctly.

Finally in line 22 we close the document. The UITest.close_doc method correctly handles the query dialog requesting confirmation that we want to discard all changes.

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.

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.


You can see the test in the repository in the uitest/calc_tests/ file. The second test in that file shows how to create a local range name by selecting the second entry in the combo box.

More blog posts and wiki pages documenting the UI test framework are going to follow soon.

If you have any question or suggestion please contact me.