Fill Strategies
This tutorial explains Widgetastic’s built-in fill strategies for handling form filling operations. You’ll learn about DefaultFillViewStrategy and WaitFillViewStrategy, how they work, and when to use each one.
Learning Objectives
By completing this tutorial, you will:
✅ Understand how fill strategies work in Widgetastic
✅ Learn when to use
DefaultFillViewStrategyvsWaitFillViewStrategy✅ Use
respect_parentfor strategy inheritance in nested views
Understanding Fill Strategies
Fill strategies control how widgets are filled in a View. When you call view.fill(values), the view uses its configured fill strategy to determine:
The order widgets should be filled
Whether to wait for widgets to appear before filling
How to handle errors during filling
What to log during fill operations
Widgetastic provides two built-in fill strategies:
Built-in Fill Strategies
DefaultFillViewStrategy: Fills widgets sequentially without waiting
WaitFillViewStrategy: Waits for each widget to be displayed before filling
DefaultFillViewStrategy
DefaultFillViewStrategy is the default strategy used by all Views. It fills widgets in the order they appear in the view’s widget_names attribute.
Key Features:
Fills widgets sequentially in order
No waiting for widgets to appear
Skips widgets with
NonevaluesWarns about extra keys that don’t match widgets
Handles widgets without fill methods gracefully
Returns
Trueif any widget value changed
Basic Usage:
"""DefaultFillViewStrategy Examples
This comprehensive example demonstrates all aspects of DefaultFillViewStrategy.
"""
from widgetastic.utils import DefaultFillViewStrategy
from widgetastic.widget import View, TextInput, Checkbox, Widget
class BasicForm(View):
input1 = TextInput(name="input1")
input2 = TextInput(name="fill_with_2")
checkbox1 = Checkbox(id="input2")
# Explicitly set the default strategy (optional - it's the default)
fill_strategy = DefaultFillViewStrategy()
# Create view instance
view = BasicForm(browser) # noqa: F821
# Fill multiple widgets at once
changed = view.fill({"input1": "test_value", "checkbox1": True})
print(f"Fill changed values: {changed}")
print(f"Current values: {view.read()}")
Filtering None Values:
Values set to None are automatically filtered out:
values_with_none = {
"input1": "value1",
"input2": None, # This will be filtered out
"checkbox1": True,
}
view.fill(values_with_none)
print(f"After filling with None values: {view.read()}")
Handling Extra Keys:
The strategy warns about keys in your fill data that don’t correspond to widgets:
import logging # noqa: E402
logging.basicConfig(level=logging.WARNING)
values_with_extras = {
"input1": "value1",
"nonexistent_widget": "value2", # This doesn't exist
"another_extra": "value3", # This doesn't exist either
}
# When filling, you'll get a warning in logs:
# "Extra values that have no corresponding fill fields passed: another_extra, nonexistent_widget"
view.fill(values_with_extras)
Handling Widgets Without Fill Methods:
Widgets that don’t have a fill() method are skipped with a warning:
class NoFillWidget(Widget):
"""Widget without fill method."""
pass
class TestForm(View):
input1 = TextInput(name="input1")
no_fill_widget = NoFillWidget()
input2 = TextInput(name="fill_with_2")
fill_strategy = DefaultFillViewStrategy()
test_view = TestForm(browser) # noqa: F821
# Fill operation will skip no_fill_widget and log a warning
values = {
"input1": "value1",
"no_fill_widget": "will_skip", # This will be skipped
"input2": "value2",
}
result = test_view.fill(values)
print(f"Fill result: {result}")
print(f"Current values: {test_view.read()}")
Change Detection:
The strategy returns True only if at least one widget value actually changed:
# First fill - values are new, so returns True
result1 = view.fill({"input1": "test_value", "checkbox1": True})
print(f"First fill result: {result1}")
# Second fill with same values - no change, returns False
result2 = view.fill({"input1": "test_value", "checkbox1": True})
print(f"Second fill result: {result2}")
WaitFillViewStrategy
WaitFillViewStrategy extends DefaultFillViewStrategy by adding wait functionality. Before filling each widget, it waits for the widget to be displayed.
Key Features:
* Inherits all features from DefaultFillViewStrategy
* Waits for each widget to be displayed before filling
* Configurable wait timeout per widget
* Ideal for dynamic content that appears after user interactions
* Handles Single Page Applications (SPAs) with async loading
When to Use:
Use WaitFillViewStrategy when:
* Widgets may appear dynamically after page load
* Forms have conditional fields that appear based on selections
* Widgets are inside iframes that load slowly
* Forms have progressive revelation of fields
Basic Usage:
"""WaitFillViewStrategy Examples
This comprehensive example demonstrates WaitFillViewStrategy usage.
"""
from widgetastic.utils import WaitFillViewStrategy
from widgetastic.widget import View, TextInput, Checkbox
class DynamicForm(View):
input1 = TextInput(name="input1")
checkbox1 = Checkbox(id="input2")
# Use wait strategy with default 5-second timeout
fill_strategy = WaitFillViewStrategy()
view = DynamicForm(browser) # noqa: F821
# Fill operation will wait for each widget to be displayed
changed = view.fill({"input1": "wait_test_value", "checkbox1": True})
print(f"Fill changed values: {changed}")
print(f"Current values: {view.read()}")
Custom Wait Timeout:
Configure how long to wait for each widget:
class DynamicFormCustomTimeout(View):
input1 = TextInput(name="input1")
input2 = TextInput(name="fill_with_2")
checkbox1 = Checkbox(id="input2")
# Custom 10-second timeout per widget
fill_strategy = WaitFillViewStrategy(wait_widget=10)
view_custom = DynamicFormCustomTimeout(browser) # noqa: F821
# Each widget will wait up to 10 seconds to be displayed
view_custom.fill({"input1": "custom_wait_test", "input2": "another_value"})
print(f"Current values: {view_custom.read()}")
Strategy Inheritance with respect_parent
Both fill strategies support the respect_parent parameter, which controls whether child views inherit the parent’s fill strategy.
Understanding respect_parent:
respect_parent=False(default): Child views get their own default strategyrespect_parent=True: Child views inherit parent’s strategy
Example Without Inheritance:
from widgetastic.utils import WaitFillViewStrategy
from widgetastic.widget import View, TextInput
# Example: Without respect_parent (default behavior)
class ParentViewNoInherit(View):
fill_strategy = WaitFillViewStrategy(wait_widget=10)
@View.nested
class ChildView(View):
input1 = TextInput(name="input1")
parent_view = ParentViewNoInherit(browser) # noqa: F821
print(f"Parent strategy: {type(parent_view.fill_strategy).__name__}")
print(f"Child strategy: {type(parent_view.ChildView.fill_strategy).__name__}")
Example With Inheritance:
# Example: With respect_parent=True
class ParentViewWithInherit(View):
fill_strategy = WaitFillViewStrategy(respect_parent=True, wait_widget=10)
@View.nested
class ChildView(View):
input1 = TextInput(name="input1")
parent_view2 = ParentViewWithInherit(browser) # noqa: F821
print(f"Parent strategy: {type(parent_view2.fill_strategy).__name__}")
print(f"Child strategy: {type(parent_view2.ChildView.fill_strategy).__name__}")
Key takeaways:
Views automatically use
DefaultFillViewStrategyif none specifiedUse
WaitFillViewStrategyfor dynamic content that may not be immediately availableFill strategies handle error cases gracefully (skipping widgets without fill methods)
Strategies respect widget order and filter None values automatically
This completes the fill strategies tutorial. You now understand how to use Widgetastic’s built-in fill strategies effectively in your automation tests.