Skip to main content
Version: Latest

Pathfinding & Multi-State Activation

Introductionโ€‹

Brobot's pathfinding system is designed to handle the reality of modern GUIs where actions often activate multiple UI elements simultaneously. Unlike traditional page-based navigation where you go from Page A to Page B, real applications often display multiple panels, sidebars, and overlays at once.

In Brobot 1.1.0, there is no concept of a "primary target state" in transitions. All states activated by a transition are treated equally for pathfinding purposes.

How Pathfinding Worksโ€‹

The State Graphโ€‹

Brobot builds a directed graph where:

  • Nodes are States (UI configurations)
  • Edges are Transitions (actions that change the UI)

Multi-State Activationโ€‹

When a transition executes, it can activate multiple states simultaneously:

import io.github.jspinak.brobot.annotations.*;
import org.springframework.stereotype.Component;

@Component
@TransitionSet(state = LoginState.class)
public class LoginTransitions {

@Autowired
private Action action;

@Autowired
private LoginState loginState;

/**
* Verify we've arrived at the Login state.
*/
@IncomingTransition(description = "Verify login screen is visible")
public boolean verifyLoginScreen() {
return action.find(loginState.getLoginButton()).isSuccess();
}

/**
* Login transition that activates multiple states.
* Transitions FROM LoginState TO Dashboard (and related states).
*/
@OutgoingTransition(
activate = {
DashboardState.class,
NavigationBarState.class,
StatusPanelState.class,
NotificationAreaState.class
}
)
public boolean login() {
return action.click(loginState.getLoginButton()).isSuccess();
}
}

Path Discovery Algorithmโ€‹

When you call navigator.openState("TargetState"), Brobot:

  1. Indexes ALL Activated States: Each transition is indexed by every state it activates
  2. Explores All Paths: The pathfinder considers transitions through ANY activated state
  3. Finds Shortest Path: Returns the path with the lowest total path cost

Example: Finding Paths Through Multi-State Transitionsโ€‹

// Given these transitions:
// State A โ†’ activates [B, C, D]
// State B โ†’ activates [E]
// State C โ†’ activates [F]
// State D โ†’ activates [G]
// State E โ†’ activates [TargetState]

// When calling:
navigator.openState("TargetState");

// Pathfinder considers these paths:
// A โ†’ B โ†’ E โ†’ TargetState โœ“ (Found via B)
// A โ†’ C โ†’ F โ†’ ... (Dead end)
// A โ†’ D โ†’ G โ†’ ... (Dead end)

// Result: Path A โ†’ B โ†’ E โ†’ TargetState is used

Important Concepts for Developersโ€‹

1. Path Success vs. Complete Activationโ€‹

Critical Understanding: Path success only requires the NEXT NODE in the path to be activated, not all activated states.

// Transition from A activates [B, C, D, E]
// Path is A โ†’ B โ†’ F

// During traversal:
// 1. Execute transition from A
// 2. Verify B is active โœ“ (Path continues)
// 3. Don't need to verify C, D, E for path success
// 4. If C, D, or E fail, path still succeeds (but log warnings)

2. IncomingTransitions Execute for ALL Activated Statesโ€‹

When a transition activates multiple states, each state's @IncomingTransition executes:

// Transition activates Dashboard, Sidebar, Header
// Execution order:
// 1. OutgoingTransition executes (leaving source state)
// 2. Dashboard.verifyArrival() executes
// 3. Sidebar.verifyArrival() executes
// 4. Header.verifyArrival() executes
// All must succeed for complete transition success

Practical Implicationsโ€‹

1. More Paths Availableโ€‹

Your automation has more navigation options:

// If Login โ†’ [Dashboard, Menu, Profile]
// Then you can reach Menu states via Login, even if
// Login's "main purpose" seems to be Dashboard

2. Flexible Navigationโ€‹

States can be reached through unexpected routes:

// UserProfile might be reached via:
// - Direct navigation: Menu โ†’ UserProfile
// - Side effect: Dashboard โ†’ [Settings, UserProfile]
// - Multi-activation: Login โ†’ [Dashboard, UserProfile, Notifications]

3. Design Considerationsโ€‹

When to Use Multi-State Activationโ€‹

โœ… Good Use Cases:

  • Login opens multiple panels simultaneously
  • Tab switches that keep navigation visible
  • Modals that overlay existing content
  • Dashboards with multiple independent widgets

โŒ Avoid When:

  • States are sequential (load one, then another)
  • Activation depends on conditions
  • States are mutually exclusive

Understanding Path Choicesโ€‹

The pathfinder chooses paths based on:

  1. Reachability: Can we get there from current active states?
  2. Path Length: Fewer transitions preferred
  3. Transition Costs: Lower path costs preferred

Best Practicesโ€‹

// Good: Logical grouping of related states
@OutgoingTransition(
activate = {
EmailComposeState.class, // Main panel
EmailToolbarState.class, // Related toolbar
RecipientListState.class // Related sidebar
}
)
public boolean openEmailCompose() {
return action.click(composeButton).isSuccess();
}

// Bad: Unrelated states that happen to appear together
@OutgoingTransition(
activate = {
EmailComposeState.class,
StockTickerState.class, // Unrelated - BAD!
WeatherWidgetState.class // Unrelated - BAD!
}
)
public boolean openEmailWithUnrelatedStuff() {
return action.click(composeButton).isSuccess();
}

Debugging Pathfindingโ€‹

# application.properties
logging.level.io.github.jspinak.brobot.navigation.path=TRACE
logging.level.io.github.jspinak.brobot.navigation.transition=TRACE

This will enable TRACE-level logging for:

  • Path package: PathFinder algorithm, path calculation, graph traversal
  • Transition package: Transition execution, state activation/deactivation

For even more detailed debugging, you could also add:

# Enable all navigation logging
logging.level.io.github.jspinak.brobot.navigation=TRACE

# Or be more specific
logging.level.io.github.jspinak.brobot.navigation.path.PathFinder=TRACE
logging.level.io.github.jspinak.brobot.navigation.transition.TransitionExecutor=TRACE
logging.level.io.github.jspinak.brobot.navigation.transition.StateNavigator=TRACE

Summaryโ€‹

Brobot's pathfinding system embraces the complexity of modern GUIs by:

  1. Treating all activated states equally - No artificial "primary" target
  2. Indexing transitions by ALL activated states - More paths available
  3. Verifying path progression, not complete activation - Flexible navigation
  4. Executing IncomingTransitions for all activated states - Proper verification

This design makes your automation more robust and adaptable to real-world GUI behaviors where multiple elements appear and disappear together.