Conditional Action Chains Examples
Overview
ConditionalActionChain provides a fluent API for building complex action sequences with conditional execution. This page demonstrates common patterns and real-world examples.
Basic Examples
Simple Find and Click
// Basic find and click pattern
ConditionalActionChain.find(new PatternFindOptions.Builder().build())
.ifFound(new ClickOptions.Builder().build())
.perform(action, new ObjectCollection.Builder()
.withImages(buttonImage)
.build());
Find with Error Handling
ConditionalActionChain.find(findOptions)
.ifFound(click())
.ifNotFoundLog("Critical button not found!")
.ifNotFoundDo(result -> {
// Custom error handling
alertUser("UI element missing");
takeDebugScreenshot();
})
.perform(action, objectCollection);
Real-World Scenarios
Login Flow
public ActionResult performLogin(String username, String password) {
return ConditionalActionChain.find(loginButton)
.ifFound(click())
.ifNotFoundLog("Login button not visible")
.ifNotFound(find(menuButton))
.ifFound(click())
.always(wait(1.0))
.then(find(usernameField))
.ifFound(click())
.ifFound(type(username))
.then(find(passwordField))
.ifFound(click())
.ifFound(type(password))
.then(find(submitButton))
.ifFound(click())
.always(wait(2.0))
.perform(action, objectCollection);
}
Save with Confirmation Dialog
public ActionResult saveWithConfirmation() {
return ConditionalActionChain.find(saveButton)
.ifFound(click())
.ifNotFoundLog("Save button not found")
.ifFound(wait(0.5))
.then(find(confirmDialog))
.ifFound(find(yesButton))
.ifFound(click())
.ifNotFound(log("No confirmation needed"))
.always(wait(1.0))
.then(find(successMessage))
.ifFoundLog("Save successful")
.ifNotFoundLog("Save may have failed")
.perform(action, objectCollection);
}
Retry Pattern
public ActionResult clickWithRetry(StateImage target, int maxRetries) {
ConditionalActionChain chain = ConditionalActionChain.find(
new PatternFindOptions.Builder()
.setSimilarity(0.8)
.build()
);
for (int i = 0; i < maxRetries; i++) {
chain = chain
.ifNotFoundLog("Attempt " + (i + 1) + " failed")
.ifNotFound(wait(1.0))
.ifNotFound(find(target));
}
return chain
.ifFound(click())
.ifFoundLog("Successfully clicked after retries")
.ifNotFoundLog("Failed after " + maxRetries + " attempts")
.perform(action, new ObjectCollection.Builder()
.withImages(target)
.build());
}
Advanced Patterns
Multi-Step Form Filling
public ActionResult fillForm(FormData data) {
return ConditionalActionChain.find(formTitle)
.ifNotFoundLog("Form not visible")
.ifNotFound(throwError("Cannot proceed without form"))
// Name field
.then(find(nameField))
.ifFound(click())
.ifFound(clearAndType(data.getName()))
// Email field
.then(find(emailField))
.ifFound(click())
.ifFound(clearAndType(data.getEmail()))
// Dropdown selection
.then(find(countryDropdown))
.ifFound(click())
.ifFound(wait(0.5))
.then(find(data.getCountry()))
.ifFound(click())
// Checkbox
.then(find(agreeCheckbox))
.ifFound(clickIfNotChecked())
// Submit
.then(find(submitButton))
.ifFound(click())
.always(takeScreenshot("form-submission"))
.perform(action, objectCollection);
}
Dynamic UI Navigation
public ActionResult navigateToSection(String sectionName) {
return ConditionalActionChain.find(hamburgerMenu)
.ifFound(click())
.ifNotFound(find(navigationBar))
.always(wait(0.5))
.then(find(sectionName))
.ifFound(click())
.ifNotFound(scrollDown())
.ifNotFound(find(sectionName))
.ifFound(click())
.ifNotFoundLog("Section '" + sectionName + "' not found")
.always(wait(1.0))
.perform(action, objectCollection);
}
Validation Chain
public ActionResult validateAndSubmit() {
return ConditionalActionChain.find(formFields)
.ifFound(validateFields())
.ifNotFoundLog("Form fields not found")
// Check for errors
.then(find(errorMessages))
.ifFoundLog("Validation errors present")
.ifFound(highlightErrors())
.ifFound(stopChain())
// No errors, proceed
.ifNotFound(find(submitButton))
.ifFound(highlight())
.ifFound(wait(1.0))
.ifFound(click())
// Verify submission
.then(waitVanish(submitButton))
.ifFoundLog("Form submitted successfully")
.ifNotFound(find(errorMessage))
.ifFoundLog("Submission failed with error")
.perform(action, objectCollection);
}
Conditional Patterns
If-Else Logic
// Check if logged in, login if not
ConditionalActionChain.find(userAvatar)
.ifFoundLog("Already logged in")
.ifNotFound(find(loginButton))
.ifFound(click())
.ifFound(performLogin())
.perform(action, objectCollection);
Switch-Like Behavior
public ActionResult handleDialog() {
return ConditionalActionChain.find(dialogBox)
// Try OK button first
.ifFound(find(okButton))
.ifFound(click())
// If no OK, try Yes button
.ifNotFound(find(yesButton))
.ifFound(click())
// If no Yes, try Continue button
.ifNotFound(find(continueButton))
.ifFound(click())
// If none found, try Close button
.ifNotFound(find(closeButton))
.ifFound(click())
// Last resort - press Escape
.ifNotFound(pressEscape())
.always(wait(0.5))
.perform(action, objectCollection);
}
Conditional Branching
public ActionResult processItem(StateImage item) {
return ConditionalActionChain.find(item)
.ifFound(analyzeItem())
// Branch based on item type
.ifFoundDo(result -> {
String itemType = result.getText();
if ("document".equals(itemType)) {
chain.then(openDocument());
} else if ("image".equals(itemType)) {
chain.then(viewImage());
} else {
chain.then(showProperties());
}
})
.always(logAction())
.perform(action, objectCollection);
}
Error Recovery
Graceful Degradation
public ActionResult saveDocument() {
return ConditionalActionChain
// Try primary save method
.find(saveButton)
.ifFound(click())
// Fallback to menu
.ifNotFound(find(fileMenu))
.ifFound(click())
.ifFound(find(saveMenuItem))
.ifFound(click())
// Fallback to keyboard shortcut
.ifNotFound(pressCtrlS())
// Verify save completed
.always(wait(1.0))
.then(find(savedIndicator))
.ifFoundLog("Document saved successfully")
.ifNotFoundLog("Save status unknown")
.perform(action, objectCollection);
}
Exception Handling
public ActionResult safeOperation() {
return ConditionalActionChain.find(dangerousButton)
.ifFound(checkPrerequisites())
.ifFoundDo(result -> {
if (!result.isSuccess()) {
throw new IllegalStateException("Prerequisites not met");
}
})
.ifFound(click())
.ifFound(wait(2.0))
.then(find(confirmationDialog))
.ifFound(handleConfirmation())
.ifNotFoundLog("Operation completed without confirmation")
.always(cleanupResources())
.perform(action, objectCollection);
}
Performance Optimization
Batch Operations
public ActionResult processAllItems() {
// Find all items once
ActionResult items = action.find(itemPattern);
if (!items.isSuccess()) {
return items;
}
// Process each item without re-finding
ActionResult finalResult = new ActionResult();
for (Match item : items.getMatchList()) {
ActionResult result = ConditionalActionChain
.start(highlightRegion(item.getRegion()))
.then(clickRegion(item.getRegion()))
.then(wait(0.5))
.then(processItemDialog())
.perform(action, emptyCollection);
finalResult.merge(result);
}
return finalResult;
}
Lazy Evaluation
public ActionResult efficientWorkflow() {
return ConditionalActionChain
// Quick check first
.find(new PatternFindOptions.Builder()
.setSimilarity(0.9)
.setSearchRegion(topBar)
.build())
.ifFound(quickAction())
// Full search only if quick check fails
.ifNotFound(find(new PatternFindOptions.Builder()
.setSimilarity(0.7)
.setSearchRegion(fullScreen)
.build()))
.ifFound(fullAction())
.perform(action, objectCollection);
}
Testing Patterns
Mock-Friendly Chains
@Test
public void testLoginChain() {
// Create test data
ObjectCollection testCollection = new ObjectCollection.Builder()
.withImages(mockLoginButton)
.build();
// Build and test chain
ActionResult result = ConditionalActionChain
.find(testFindOptions)
.ifFound(testClickOptions)
.ifNotFoundLog("Test: Login button not found")
.perform(mockAction, testCollection);
// Verify behavior
assertTrue(result.isSuccess());
assertEquals("Test: Login button not found",
result.getText());
}
Best Practices
- Keep Chains Readable: Break complex chains into named methods
- Use Logging: Add ifFoundLog/ifNotFoundLog for debugging
- Handle Failures: Always provide ifNotFound alternatives
- Test Incrementally: Build chains step by step
- Reuse Common Patterns: Create utility methods for repeated sequences
Common Pitfalls
- Forgetting always(): Use for cleanup that must happen
- Long Chains: Break into smaller, named sub-chains
- Missing Error Handling: Always handle the ifNotFound case
- Tight Coupling: Keep chains focused on single workflows