Action Refactoring Migration Guide
Overview
Brobot is undergoing a significant architectural improvement to separate Find operations from other actions. This refactoring enables better testing, cleaner code, and more flexible action composition. This guide will help you migrate your code to use the new pure actions and conditional action chains.
Key Changes
1. Separation of Find from Actions
Before: Actions like Click, Highlight, and Type had Find operations embedded within them.
// Old approach - Find is hidden inside Click
action.click(stateImage);
After: Find is now a separate operation that can be chained with pure actions.
// New approach - Explicit Find then Click
ConditionalActionChain.find(findOptions)
.ifFound(clickOptions)
.perform(action, objectCollection);
2. Pure Actions
We've introduced "pure" actions that only perform their core function without any Find operations:
ClickV2
- Pure click operationsHighlightV2
- Pure highlight operationsTypeV2
- Pure typing operations- More pure actions coming soon
3. Convenience Methods
The Action class now provides convenience methods for common operations:
// Simple one-line operations
action.perform(ActionType.CLICK, location);
action.perform(ActionType.HIGHLIGHT, region);
action.perform(ActionType.TYPE, "Hello World");
Migration Examples
Example 1: Click on an Image
Old Code:
ClickOptions options = new ClickOptions.Builder()
.setClickType(ClickOptions.Type.LEFT)
.build();
action.perform(options, stateImage);
New Code (Explicit):
ConditionalActionChain.find(new PatternFindOptions.Builder().build())
.ifFound(new ClickOptions.Builder().build())
.perform(action, new ObjectCollection.Builder()
.withImages(stateImage)
.build());
New Code (Convenience):
// First find the image
ActionResult findResult = action.find(stateImage);
// Then click if found
if (findResult.isSuccess()) {
action.perform(ActionType.CLICK, findResult.getMatchList().get(0).getRegion());
}
Example 2: Type in a Field
Old Code:
TypeOptions options = new TypeOptions.Builder()
.setText("Hello World")
.build();
action.perform(options, textFieldImage);
New Code:
ConditionalActionChain.find(new PatternFindOptions.Builder().build())
.ifFound(new TypeOptions.Builder()
.setText("Hello World")
.build())
.perform(action, new ObjectCollection.Builder()
.withImages(textFieldImage)
.build());
Example 3: Highlight Multiple Regions
Old Code:
HighlightOptions options = new HighlightOptions.Builder()
.setHighlightDuration(2.0)
.build();
action.perform(options, objectCollection);
New Code (Direct highlight without Find):
// If you already have regions to highlight
action.perform(ActionType.HIGHLIGHT, region1, region2, region3);
New Code (Find then highlight):
ConditionalActionChain.find(findOptions)
.ifFound(new HighlightOptions.Builder()
.setHighlightDuration(2.0)
.build())
.perform(action, objectCollection);
Example 4: Complex Action Chains
Old Code:
// Had to use multiple action calls
ActionResult result1 = action.find(loginButton);
if (result1.isSuccess()) {
action.click(loginButton);
action.type(usernameField, username);
action.type(passwordField, password);
action.click(submitButton);
}
New Code:
ConditionalActionChain.find(loginButton)
.ifFound(click())
.then(find(usernameField))
.ifFound(type(username))
.then(find(passwordField))
.ifFound(type(password))
.then(find(submitButton))
.ifFound(click())
.perform(action, objectCollection);
Using Pure Actions Directly
Pure actions can be used directly when you already have locations or regions:
// Direct click on a known location
Location buttonLocation = new Location(100, 200);
action.perform(ActionType.CLICK, buttonLocation);
// Direct highlight on a region
Region area = new Region(50, 50, 200, 100);
action.perform(ActionType.HIGHLIGHT, area);
// Type at current cursor position
action.perform(ActionType.TYPE, "Hello World");
Backward Compatibility
Deprecation Timeline
-
Version 2.0: Introduction of pure actions and ConditionalActionChain
- Old actions still work but show deprecation warnings
- New actions available as V2 versions (ClickV2, TypeV2, etc.)
-
Version 2.5: Old actions moved to legacy package
- Import statements will need updating
- Functionality remains the same
-
Version 3.0: Legacy actions removed
- Full migration required
Using Composite Actions
For users who prefer the old single-method approach, we provide composite actions:
// Composite action that combines Find and Click
FindAndClick findAndClick = new FindAndClick(findOptions, clickOptions);
action.perform(findAndClick, stateImage);
Benefits of Migration
- Better Testing: Test click logic without mocking Find operations
- Performance: Find once, act multiple times on the same matches
- Clarity: Explicit separation between finding and acting
- Flexibility: Build complex conditional chains easily
- Debugging: Clear distinction between find failures and action failures
Common Patterns
Pattern 1: Find Once, Act Multiple Times
ActionResult matches = action.find(targetImage);
if (matches.isSuccess()) {
for (Match match : matches.getMatchList()) {
action.perform(ActionType.HIGHLIGHT, match.getRegion());
Thread.sleep(500);
action.perform(ActionType.CLICK, match.getRegion());
}
}
Pattern 2: Conditional Actions
ConditionalActionChain.find(saveButton)
.ifFound(click())
.ifNotFound(log("Save button not found, trying alt method"))
.ifNotFound(find(altSaveButton))
.ifFound(click())
.always(takeScreenshot())
.perform(action, objectCollection);
Pattern 3: Validation Chains
ConditionalActionChain.find(dialogBox)
.ifFound(highlight())
.then(find(confirmButton))
.ifFound(click())
.then(waitVanish(dialogBox))
.ifNotFound(throwError("Dialog didn't close"))
.perform(action, objectCollection);
Migration Checklist
- Identify all uses of embedded Find in actions
- Replace with ConditionalActionChain or pure actions
- Update imports for new action classes
- Test thoroughly - behavior should be identical
- Consider using convenience methods for simple cases
- Update any custom actions to follow the new pattern
Getting Help
- See the API Reference for detailed documentation
- Check Examples for more usage patterns
- File issues at the Brobot GitHub repository
Next Steps
- Start with high-impact areas of your code
- Migrate incrementally - both old and new APIs work together
- Use the deprecation warnings as a guide
- Take advantage of the new flexibility to simplify complex workflows