ActionHistory and Mock Snapshots
Overview
ActionHistory is a critical component for mock mode testing in Brobot. It provides historical data about pattern matches and actions, enabling realistic simulation of GUI interactions without actual screen access. This is required for patterns to be "found" in mock mode.
Key Concepts
What is ActionHistory?
ActionHistory stores a collection of ActionRecord
objects that represent past interactions with GUI elements. Each record contains:
- Match information (location, similarity score)
- Action configuration (find options, strategies)
- Success/failure status
- Execution duration
Why ActionHistory is Required in Mock Mode
In mock mode, Brobot doesn't perform real pattern matching. Instead, it uses ActionHistory to:
- Determine if a pattern should be "found"
- Provide realistic match locations and scores
- Simulate timing and performance characteristics
- Enable deterministic or probabilistic testing
Important: Without ActionHistory, patterns will never be found in mock mode, causing all find operations to fail.
New Builder Integration (v1.0.0+)
Starting with Brobot v1.0.0, ActionHistory can be configured directly in the StateImage builder, eliminating the need for separate initialization methods.
Basic Usage
import io.github.jspinak.brobot.model.state.StateImage;
import io.github.jspinak.brobot.model.element.Region;
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryFactory;
// Create a StateImage with ActionHistory in one step
StateImage button = new StateImage.Builder()
.addPatterns("button/ok-button.png")
.setName("OkButton")
.withActionHistory(MockActionHistoryFactory.reliableButton(
new Region(100, 200, 80, 30)))
.build();
StateImage.Builder Methods
The StateImage.Builder class provides three methods for setting ActionHistory:
1. Direct ActionHistory
ActionHistory history = createCustomHistory();
StateImage image = new StateImage.Builder()
.addPatterns("pattern.png")
.withActionHistory(history)
.build();
2. Supplier Function (Lazy Initialization)
StateImage image = new StateImage.Builder()
.addPatterns("pattern.png")
.withActionHistory(() -> createComplexHistory())
.build();
3. Single ActionRecord
ActionRecord record = createSingleRecord();
StateImage image = new StateImage.Builder()
.addPatterns("pattern.png")
.withActionHistory(record)
.build();
MockActionHistoryBuilder
The MockActionHistoryBuilder
provides a fluent API for creating custom ActionHistory configurations.
Basic Configuration
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryBuilder;
ActionHistory history = MockActionHistoryBuilder.builder()
.successRate(0.95) // 95% success rate
.matchRegion(region) // Where matches occur
.minSimilarity(0.90) // Minimum similarity score
.maxSimilarity(0.99) // Maximum similarity score
.minDuration(30) // Minimum execution time (ms)
.maxDuration(100) // Maximum execution time (ms)
.recordCount(20) // Number of records to generate
.build()
.build();
Preset Configurations
MockActionHistoryBuilder provides preset methods for common scenarios:
// Always found (100% success)
ActionHistory reliable = MockActionHistoryBuilder.Presets.alwaysFound(region);
// Highly reliable (95% success)
ActionHistory good = MockActionHistoryBuilder.Presets.reliable(region);
// Flaky element (70% success)
ActionHistory unstable = MockActionHistoryBuilder.Presets.flaky(region);
// Never found (0% success)
ActionHistory missing = MockActionHistoryBuilder.Presets.neverFound();
MockActionHistoryFactory
The MockActionHistoryFactory
provides factory methods for common UI patterns and screen positions.
UI Pattern Methods
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryFactory;
// Reliable button (98% success, quick response)
ActionHistory button = MockActionHistoryFactory.reliableButton(buttonRegion);
// Dynamic text field (85% success, variable content)
ActionHistory textField = MockActionHistoryFactory.dynamicTextField(fieldRegion);
// Loading indicator (60% success, appears/disappears)
ActionHistory loader = MockActionHistoryFactory.loadingIndicator(loaderRegion);
// Menu item (90% success when visible)
ActionHistory menuItem = MockActionHistoryFactory.menuItem(menuRegion);
// Modal dialog (100% success when present)
ActionHistory dialog = MockActionHistoryFactory.modalDialog(dialogRegion);
Screen Position Helpers
import io.github.jspinak.brobot.model.element.Positions;
// Element at specific screen position
ActionHistory centerElement = MockActionHistoryFactory.forScreenPosition(
Positions.Name.MIDDLEMIDDLE, 100, 50); // width=100, height=50
// Element in lower-left (common for status/chat)
ActionHistory lowerLeft = MockActionHistoryFactory.lowerLeftElement(200, 80);
Custom Configuration
// Use custom configuration with lambda
ActionHistory custom = MockActionHistoryFactory.withConfig(config ->
config.successRate(0.85)
.recordCount(15)
.matchRegion(new Region(100, 100, 50, 50))
.minDuration(20)
.maxDuration(80));
Caching for Performance
// Cache frequently used histories
ActionHistory cached = MockActionHistoryFactory.cached("main-button",
() -> MockActionHistoryFactory.reliableButton(buttonRegion));
// Clear cache between test suites
MockActionHistoryFactory.clearCache();
Complete Example: Claude Automator
Here's a real-world example showing how to use the new ActionHistory features in a state class:
package com.claude.automator.states;
import io.github.jspinak.brobot.annotations.State;
import io.github.jspinak.brobot.model.element.Region;
import io.github.jspinak.brobot.model.state.StateImage;
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryFactory;
import lombok.Getter;
@State(initial = true)
@Getter
public class PromptState {
private final StateImage claudePrompt;
public PromptState() {
// Define search region for lower-left quarter of screen
Region lowerLeftQuarter = Region.builder()
.withScreenPercentage(0.0, 0.5, 0.5, 0.5)
.build();
// Create StateImage with integrated ActionHistory for mock mode
claudePrompt = new StateImage.Builder()
.addPatterns("prompt/claude-prompt-1.png",
"prompt/claude-prompt-2.png",
"prompt/claude-prompt-3.png")
.setName("ClaudePrompt")
.setSearchRegionForAllPatterns(lowerLeftQuarter)
.setFixedForAllPatterns(true)
// ActionHistory is required for mock mode finds
.withActionHistory(MockActionHistoryFactory.lowerLeftElement(293, 83))
.build();
}
}
Migration from Manual ActionHistory
Old Approach (Pre-v1.0.0)
public class MyState {
private final StateImage button;
public MyState() {
button = new StateImage.Builder()
.addPatterns("button.png")
.build();
// Separate method required
createMockActionHistory();
}
private void createMockActionHistory() {
ActionHistory history = new ActionHistory();
// Manual creation of records...
for (Pattern pattern : button.getPatterns()) {
pattern.setMatchHistory(history);
}
}
}
New Approach (v1.0.0+)
public class MyState {
private final StateImage button;
public MyState() {
// Everything in one builder chain
button = new StateImage.Builder()
.addPatterns("button.png")
.withActionHistory(MockActionHistoryFactory.reliableButton(
new Region(100, 200, 80, 30)))
.build();
}
}
Best Practices
1. Always Set ActionHistory for Mock Mode
// Check if mock mode is enabled
if (FrameworkSettings.mock) {
stateImage = new StateImage.Builder()
.addPatterns("pattern.png")
.withActionHistory(MockActionHistoryFactory.reliable(region))
.build();
}
2. Use Appropriate Factory Methods
Match the factory method to your UI element type:
- Buttons →
reliableButton()
- Text fields →
dynamicTextField()
- Loading indicators →
loadingIndicator()
- Menus →
menuItem()
- Dialogs →
modalDialog()
3. Configure Realistic Success Rates
// Critical elements should have high success rates
StateImage saveButton = new StateImage.Builder()
.addPatterns("save.png")
.withActionHistory(MockActionHistoryBuilder.builder()
.successRate(0.98) // Very reliable
.build().build())
.build();
// Optional elements can have lower rates
StateImage tooltip = new StateImage.Builder()
.addPatterns("tooltip.png")
.withActionHistory(MockActionHistoryBuilder.builder()
.successRate(0.70) // Sometimes visible
.build().build())
.build();
4. Use Screen-Adaptive Regions
// Use percentage-based regions for resolution independence
Region adaptiveRegion = Region.builder()
.withScreenPercentage(0.4, 0.4, 0.2, 0.2) // Center 20% of screen
.build();
StateImage centerElement = new StateImage.Builder()
.addPatterns("center.png")
.withActionHistory(MockActionHistoryFactory.reliable(adaptiveRegion))
.build();
5. Leverage Caching for Performance
// Cache histories that are used multiple times
public class StateFactory {
private static final String BUTTON_CACHE_KEY = "main-button";
public StateImage createButton() {
return new StateImage.Builder()
.addPatterns("button.png")
.withActionHistory(MockActionHistoryFactory.cached(
BUTTON_CACHE_KEY,
() -> MockActionHistoryFactory.reliableButton(buttonRegion)))
.build();
}
}
Troubleshooting
Patterns Not Found in Mock Mode
Problem: Find operations fail with "No matches found" despite mock mode being enabled.
Solution: Ensure ActionHistory is set:
// ❌ Wrong - No ActionHistory
StateImage image = new StateImage.Builder()
.addPatterns("pattern.png")
.build();
// ✅ Correct - ActionHistory included
StateImage image = new StateImage.Builder()
.addPatterns("pattern.png")
.withActionHistory(MockActionHistoryFactory.reliable(region))
.build();
Compilation Errors
Problem: "cannot find symbol: MockActionHistoryFactory"
Solution: Add the required import:
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryFactory;
import io.github.jspinak.brobot.tools.testing.mock.history.MockActionHistoryBuilder;
Inconsistent Test Results
Problem: Tests pass/fail randomly in mock mode.
Solution: Use deterministic success rates:
// For deterministic tests, use 100% or 0% success rates
ActionHistory alwaysFound = MockActionHistoryBuilder.Presets.alwaysFound(region);
ActionHistory neverFound = MockActionHistoryBuilder.Presets.neverFound();
Related Documentation
- Mock Mode Guide - Complete mock mode reference
- Integration Testing - Testing strategies
- Profile-Based Architecture - Test profile configuration
- StateImage API - StateImage builder reference