# Debugging your FSM

FSM2 provides a number of tools to help debug your FSM.

Firstly we strongly recommend that you only use the static transitions (i.e. don't use onDynamic). As yet we have found no use cases where onDynamic is needed and it makes debugging your FSM much harder.

## Static Analysis

The first thing you should ALWAYS check is that your FSM is consistent.

You can do this by calling [analysis](/debugging-your-fsm/static-analysis.md)().

```
statemachine.analysis();
```

You should create a unit test that tests your statemachine.

```dart
import 'package:fsm2/fsm2.dart';
import 'package:test/test.dart';

void main() {
  test('export', () async {
    final machine = _createMachine();
    expect(await machine.analyse(), equals(true));
  });
}

StateMachine _createMachine() {
  return StateMachine.create((g) => g
    ..initialState<Heating>()
    ..state<DoorOpen>((b) {})
    ..state<Heating>((b) => b
      ..on<OpenDoor, DoorOpen>()
      ..state<Toasting>((b) {})
      ..state<Baking>((b) {})));

}
class DoorOpen extends State {}
class Toasting extends State {}
class Baking extends State {}
class Heating extends State {}
class LightOn extends State {}
class OpenDoor extends Event {}
class OnTurnOff extends Event {}
```

## Visualise your FSM

If you have followed our recommendation to not use 'onDynamic' then you can create a visualisation of your FSM.

```dart
void main() {
    final machine = _createMachine();
    await machine.export('test/test.gv');
  }
```

See details on [visualisation](/visualise-your-fsm.md) for details on viewing the .gv file.

## Simplify your FSM

We are not big fans of humongous state machines. Rather we recommend that you create a statemachine for each part of your code.

You might have an FSM for each screen or particular db updates but avoid the temptation to model your entire app as a single statemachine. This will never end well.

## Log Transitions

The statemachine allows you to hook every transition by calling 'onTransition'.

```dart
  StateMachine.create((g) => g
      ..initialState<Solid>()
      ..state<Solid>((b) => b
        ..on<OnMelted, Liquid>(sideEffect: (e) => watcher.log(onMeltedMessage))
        ..onEnter((s, e) => watcher?.onEnter(s))
        ..onExit((s, e) => watcher?.onExit(s)))
      ..onTransition((fromState, event, toState) => print('${fromState} ${event} ${toState} ')));
```

The above code prints the eventType, fromState, and toState for every transition.

{% hint style="info" %}
A single event can result in multiple transitions if your state machine is in a concurrent region.
{% endhint %}

## Unit Testing

We provide a number of helper functions that make it easier to unit test your statemachine.

* StateMachine.waitUntilQuiescent
* StateMachine.isInState
* StateMachine.stateOfMind

```dart

  test('test fsm', () async {
      final machine = _createMachine<Solid>(watcher);
      machine.applyEvent(OnMelted());
      // wait for the event to have been applied
      await machine.waitUntilQuiescent;
      expect(machine.isInState<Liquid>(), equals(true));
  });
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fsm2.onepub.dev/debugging-your-fsm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
