> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goakt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# TestKit

> Testing helpers for actor systems and grains.

The `testkit` package provides helpers for actor-level testing. It creates a throwaway actor system, probes for message assertions, and supports grain testing.

## TestKit

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
    kit := testkit.New(ctx, t, testkit.WithLogging(log.DebugLevel), testkit.WithExtensions(ext))
    defer kit.Shutdown(ctx)
```

| Method                                                   | Purpose                                                               |
| -------------------------------------------------------- | --------------------------------------------------------------------- |
| `ActorSystem()`                                          | Access the underlying actor system.                                   |
| `Spawn(ctx, name, actor, opts...)`                       | Spawn an actor. Fails the test on error.                              |
| `SpawnChild(ctx, childName, parentName, actor, opts...)` | Spawn a child of an existing actor.                                   |
| `Subscribe()`                                            | Create an event-stream subscriber. Auto-unsubscribes on test cleanup. |
| `Kill(ctx, name)`                                        | Stop an actor by name.                                                |
| `NewProbe(ctx)`                                          | Create a test probe.                                                  |
| `NewGrainProbe(ctx)`                                     | Create a grain test probe.                                            |
| `GrainOf[T](ctx, kit, name, opts...)`                    | Create a grain identity of kind T (package-level function).           |
| `Shutdown(ctx)`                                          | Stop the actor system.                                                |

### Options

| Option                   | Purpose                                   |
| ------------------------ | ----------------------------------------- |
| `WithLogging(level)`     | Enable logging at the given level.        |
| `WithExtensions(ext...)` | Register extensions with the test system. |

## Probe

A probe is a test actor that records messages. Use it to assert message delivery instead of sleeps or polling.

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
    probe := kit.NewProbe(ctx)
    defer probe.Stop()
    kit.Spawn(ctx, "worker", NewWorkerActor())
    probe.Send("worker", msg)
    probe.ExpectMessage(expected)
```

### Probe interface

| Method                                               | Purpose                                                                      |
| ---------------------------------------------------- | ---------------------------------------------------------------------------- |
| `ExpectMessage(msg)`                                 | Assert the next message exactly matches `msg`. Fails on timeout or mismatch. |
| `ExpectMessageWithin(d, msg)`                        | Same with custom timeout.                                                    |
| `ExpectMessageOfType(msg)`                           | Assert the next message has the same type as `msg`.                          |
| `ExpectMessageOfTypeWithin(d, msg)`                  | Same with custom timeout.                                                    |
| `ExpectNoMessage()`                                  | Assert no message arrives within the default timeout.                        |
| `ExpectAnyMessage()`                                 | Wait for and return the next message.                                        |
| `ExpectAnyMessageWithin(d)`                          | Same with custom timeout.                                                    |
| `ExpectTerminated(actorName)`                        | Assert a `Terminated` message for the given actor.                           |
| `ExpectTerminatedWithin(actorName, d)`               | Same with custom timeout.                                                    |
| `ExpectMessageMatching(predicate)`                   | Assert the next message satisfies the predicate function.                    |
| `ExpectChildSpawned(parentName, childName)`          | Assert a child actor was spawned by the given parent.                        |
| `ExpectChildSpawnedWithin(parentName, childName, d)` | Same with custom timeout.                                                    |
| `ClearMessages()`                                    | Drain all pending messages from the probe's queue.                           |
| `Send(actorName, msg)`                               | Tell the named actor (fire-and-forget).                                      |
| `SendSync(actorName, msg, timeout)`                  | Ask the named actor; record the response in the probe.                       |
| `Sender()`                                           | PID of the sender of the last received message.                              |
| `PID()`                                              | PID of the probe itself (use as sender in tests).                            |
| `Watch(pid)`                                         | Subscribe to termination of `pid`.                                           |
| `WatchNamed(actorName)`                              | Subscribe to termination of the named actor.                                 |
| `Stop()`                                             | Shutdown the probe. Call in cleanup.                                         |

Default timeout is 3 seconds. Probes work in both standalone and cluster mode.

### Asserting child actor creation

When an actor spawns a child during message handling, use `ExpectChildSpawned` to verify:

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
func TestSpawnsChild(t *testing.T) {
    ctx := context.Background()
    kit := testkit.New(ctx, t)
    defer kit.Shutdown(ctx)

    probe := kit.NewProbe(ctx)
    defer probe.Stop()

    kit.Spawn(ctx, "parent", NewParentActor())
    probe.ExpectChildSpawned("parent", "worker")
}
```

## GrainProbe

Similar to Probe but for grains. Use the package-level `testkit.GrainOf[T]` function (or `testkit.NodeGrainOf[T]` on a
cluster test node) to create identities, then send and assert responses.

| Method                             | Purpose                                |
| ---------------------------------- | -------------------------------------- |
| `ExpectResponse(msg)`              | Assert the next response matches.      |
| `ExpectResponseWithin(d, msg)`     | Same with custom timeout.              |
| `ExpectResponseOfType(msg)`        | Assert type match.                     |
| `ExpectNoResponse()`               | Assert no response within timeout.     |
| `ExpectAnyResponse()`              | Wait for and return the next response. |
| `ExpectTerminated(identity, d)`    | Assert grain termination.              |
| `Send(identity, msg)`              | Tell the grain.                        |
| `SendSync(identity, msg, timeout)` | Ask the grain; record response.        |
| `Stop()`                           | Shutdown the probe.                    |

## MultiNodes

For integration tests, `MultiNodes` creates an in-process multi-node cluster. See `testkit/multi_nodes.go` for usage. Requires cluster and remoting configuration.

## Usage pattern

```go theme={"theme":{"light":"github-light","dark":"dracula"}}
func TestWorker(t *testing.T) {
    ctx := context.Background()
    kit := testkit.New(ctx, t)
    defer kit.Shutdown(ctx)

    probe := kit.NewProbe(ctx)
    defer probe.Stop()

    kit.Spawn(ctx, "worker", NewWorkerActor())
    probe.Send("worker", &DoWork{ID: "1"})
    probe.ExpectMessage(&WorkDone{ID: "1"})
}
```
