Open UI Automation (OUIA)
Widgetastic provides comprehensive support for OUIA (Open UI Automation) compatible components. OUIA is a specification that standardizes component identification through HTML data attributes, making automation more reliable and maintainable.
In order to start creating an OUIA compatible widget or view, just inherit from the appropriate base class.
Children classes should define the OUIA_COMPONENT_TYPE class attribute to match the value of
data-ouia-component-type attribute of the root HTML element.
The key advantage is that you don’t need to specify any locator. If a component complies with OUIA spec, the locator can be automatically generated from the OUIA attributes.
OUIA Base Classes
Widgetastic provides three base classes for OUIA support:
widgetastic.ouia.OUIABase: Core OUIA functionalitywidgetastic.ouia.OUIAGenericWidget: Base for OUIA-compatible widgetswidgetastic.ouia.OUIAGenericView: Base for OUIA-compatible views
Creating OUIA Widgets
Consider this HTML excerpt:
<button data-ouia-component-type="PF/Button" data-ouia-component-id="This is a button">
This is a button
</button>
According to OUIA, this is a Button component in the PF namespace with id This is a button.
Based on that information, we can create the following widget:
1"""Creating OUIA Widgets
2
3This example demonstrates creating and using OUIA-compatible widgets.
4"""
5
6from widgetastic.ouia import OUIAGenericWidget
7from widgetastic.widget import View
8
9
10class Button(OUIAGenericWidget):
11 """OUIA Button widget following PF (PatternFly) namespace."""
12
13 OUIA_COMPONENT_TYPE = "PF/Button"
14
15
16class Details(View):
17 button = Button(component_id="This is a button")
18
19
20view = Details(browser) # noqa: F821
21
22print(f"Button is displayed: {view.button.is_displayed}")
23print("Clicking button...")
24view.button.click()
25print("Button clicked successfully")
Creating OUIA Views
OUIA views are containers that use OUIA attributes for identification. They’re perfect for organizing multiple OUIA widgets together.
1"""Creating OUIA Views
2
3This example demonstrates creating OUIA views as containers for OUIA widgets.
4"""
5
6from widgetastic.ouia import OUIAGenericView, OUIAGenericWidget
7
8
9class Button(OUIAGenericWidget):
10 OUIA_COMPONENT_TYPE = "PF/Button"
11
12
13class TestView(OUIAGenericView):
14 """OUIA view containing multiple OUIA widgets."""
15
16 OUIA_COMPONENT_TYPE = "TestView"
17 OUIA_ID = "ouia" # Optional: default component_id for the view
18
19 button = Button(component_id="This is a button")
20
21
22view = TestView(browser) # noqa: F821
23
24# OUIA_COMPONENT_TYPE is used to generate ROOT for this view
25print(f"ROOT locator for this view: {view.ROOT}")
26
27print(f"View is displayed: {view.is_displayed}")
28
29print("Clicking button inside OUIA view...")
30view.button.click()
31print("Button clicked successfully")
Existing OUIA Widgets
Widgetastic provides some basic pre-built OUIA widgets that you can use directly:
widgetastic.ouia.input.TextInput- OUIA version of TextInput widgetwidgetastic.ouia.checkbox.Checkbox- OUIA version of Checkbox widgetwidgetastic.ouia.text.Text- OUIA version of Text widget
OUIA Safety Attribute
The data-ouia-safe attribute indicates whether a component is in a static state (no animations).
This is useful for waiting until components are ready for interaction.
1"""OUIA Safety Attribute
2
3This example demonstrates using the data-ouia-safe attribute.
4"""
5
6from widgetastic.ouia import OUIAGenericWidget
7
8# Create OUIA widgets
9button = OUIAGenericWidget(
10 parent=browser, # noqa: F821
11 component_id="This is a button",
12 component_type="PF/Button",
13)
14
15select = OUIAGenericWidget(parent=browser, component_id="some_id", component_type="PF/Select") # noqa: F821
16
17# Check if components are in a static state (no animations)
18print(f"Button is safe: {button.is_safe}")
19print(f"Select is safe: {select.is_safe}")
20
21# You can wait for a component to be safe before interacting
22print("Waiting for button to be safe before clicking...")
23if button.is_safe:
24 button.click()
25 print("Button clicked after verifying it's safe")
Complete Example
Here’s a complete example using OUIA widgets from the testing page:
1"""Complete OUIA Example
2
3This example demonstrates a comprehensive OUIA setup with multiple widgets.
4"""
5
6from widgetastic.ouia import OUIAGenericView, OUIAGenericWidget
7from widgetastic.ouia.checkbox import Checkbox
8from widgetastic.ouia.input import TextInput
9from widgetastic.ouia.text import Text
10
11
12# Define custom OUIA widget
13class Button(OUIAGenericWidget):
14 OUIA_COMPONENT_TYPE = "PF/Button"
15
16
17# Create comprehensive OUIA view
18class TestView(OUIAGenericView):
19 OUIA_COMPONENT_TYPE = "TestView"
20 OUIA_ID = "ouia"
21
22 button = Button(component_id="This is a button")
23 text = Text(component_id="unique_id", component_type="Text")
24 text_input = TextInput(component_id="unique_id", component_type="TextInput")
25 checkbox = Checkbox(component_id="unique_id", component_type="CheckBox")
26
27
28# Use the view
29view = TestView(browser) # noqa: F821
30
31print("Testing OUIA widgets:")
32view.button.click()
33print("✓ Button clicked successfully")
34
35view.text_input.fill("Test")
36print(f"✓ Text input value: {view.text_input.read()}")
37
38view.checkbox.fill(True)
39print(f"✓ Checkbox checked: {view.checkbox.read()}")
40
41print(f"✓ Text widget value: {view.text.read()}")
Key Points
Use
OUIAGenericWidgetfor individual components (buttons, inputs, etc.)Use
OUIAGenericViewfor container components (forms, sections, selects)Define
OUIA_COMPONENT_TYPEin widget classes to matchdata-ouia-component-typeUse
component_idparameter to matchdata-ouia-component-idattributeNo manual locators needed - they’re automatically generated
Component types and IDs are case-sensitive - match exactly