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

# Editor testing

> The Almedia API — SDK 1.3.0 and newer. Synced from the source repository.

Editor-only test hook for driving the SDK into any state (status, error, notifications, in-game reward grants, progress, native log) from a play-mode test or an editor host script. See [Driving non-happy paths](https://docs.almedia.dev/technical/integration-guide/editor-and-play-mode.md#driving-non-happy-paths) in the integration guide for the narrative.

The API lives in `AlmediaSDK.Editor.Testing` (assembly `AlmediaLink.Editor`, `includePlatforms:["Editor"]`). Host references must be wrapped in `#if UNITY_EDITOR` so they don't reach iOS/Android player compilation.

***

## `AlmediaEditorMock`

Namespace: `AlmediaSDK.Editor.Testing` · static class

The first call to any method here puts the underlying editor mock into **manual mode** for the rest of the play session: every subsequent `Initialize` / `StartLinking` / `FetchNotifications` becomes a no-op so canned coroutines cannot race against test emissions, and any already-scheduled simulate coroutine is cancelled on the flip. Manual mode resets on domain reload.

Every method **throws `InvalidOperationException`** if called before `Almedia.Initialize` - the throw is deliberate so test ordering bugs surface at test-author time instead of as silent no-ops. A `null` status, code, screen, result, level, task, balance or change throws `ArgumentNullException`.

### `static void EmitStatus(AlmediaStatus status)`

Delivers `status` as if native had reported it. `Status` equals it afterwards, and `OnStatusChanged` fires as it would for a native report - not at all when the status equals the current one. No `yield return` is needed before reading.

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
// Holdout player.
AlmediaEditorMock.EmitStatus(new AlmediaStatus.NotAvailable("holdout"));

// Linking declared in DisabledFeatures - the bundled LinkButton hides.
AlmediaEditorMock.EmitStatus(new AlmediaStatus.NotAvailable("disabled"));

// Linked, but the reward hub is gone - the bundled LinkButton hides.
AlmediaEditorMock.EmitStatus(new AlmediaStatus.Linked(false, false));
```

### `static void EmitError(AlmediaErrorCode code, string message)`

Fires `OnErrorOccurred` with the given code and message. Use this to exercise error-handling UI under every [`AlmediaErrorCode`](https://docs.almedia.dev/technical/api-reference/almedia/models#almediaerrorcode).

### `static void EmitLinkCompleted()`

Fires `OnLinkCompleted` with the current UTC timestamp. Use it to test "celebrate a fresh link" UX in isolation from the linking flow itself.

### `static void EmitNotifications(params AlmediaNotification[] notifications)`

Fires `OnNotificationsReceived` with the supplied notifications, delivered through the same bridge path the native plugins use. Pass no arguments for an empty batch (note: the SDK short-circuits empty batches and does **not** raise `OnNotificationsReceived` - useful for verifying the "no new rewards" branch on the SDK side). A notification without a timestamp arrives with an empty `Timestamp` and a `null` `ReceivedAt`.

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
AlmediaEditorMock.EmitNotifications(new AlmediaNotification("n-1", "Reward", "You earned 100 coins",
    DateTime.UtcNow.ToString("o"), "popup", null));
```

### `static void EmitInGameRewardGrant(params AlmediaInGameReward[] rewards)`

Fires `OnInGameRewardGrantRequested` with a generated grant id and the current UTC timestamp, delivered through the same bridge path the native plugins use. Pass at least one reward; the SDK drops a rewardless grant as malformed, which a bare `EmitInGameRewardGrant()` can exercise.

### `static void EmitInGameRewardGrant(string id, params AlmediaInGameReward[] rewards)`

Same, with an explicit grant id (null or empty generates one). Delivery on device is at-least-once, so call this twice with the same id to reproduce a redelivered grant and verify your dedup:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
var rewards = new[] { new AlmediaInGameReward(250, "gems"), new AlmediaInGameReward(3, "spins") };
AlmediaEditorMock.EmitInGameRewardGrant("grant-1", rewards);
AlmediaEditorMock.EmitInGameRewardGrant("grant-1", rewards);   // must credit once
```

### `static void EmitProgress(AlmediaProgress progress)`

Applies `progress` as the latest snapshot. It uses the same bridge path as the native plugins. `Almedia.Progress` holds the snapshot and `OnProgressUpdated` fires on the same call. Pass `null` to model the native SDK clearing the snapshot: the accessor becomes `null` and the event fires with `null`. Build a snapshot with the public constructors. Pass a `null` username to model a snapshot that clears the previous username:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
var points = new AlmediaRewardPoints(12500, new AlmediaMoney(11.50m, "EUR"), new AlmediaMoney(12.50m, "USD"));
var task = new AlmediaTask("t-1", AlmediaTaskKind.Burning, "Reach level 10", points, new AlmediaTaskProgress(3, 10),
    DateTimeOffset.UtcNow.AddHours(2).ToString("o"));                          // RewardDropsAt in two hours
AlmediaEditorMock.EmitProgress(new AlmediaProgress("s-1", "2026-09-14T10:00:00.000Z", "demo_player",
    points, points, new[] { task }, new AlmediaCompletedTask[0], new AlmediaTask[0]));
AlmediaEditorMock.EmitProgress(new AlmediaProgress("s-2", "2026-09-14T10:01:00.000Z", null,
    points, points, new[] { task }, new AlmediaCompletedTask[0], new AlmediaTask[0]));   // Username reads null
AlmediaEditorMock.EmitProgress(null);                                          // Progress reads null
```

### `static void EmitTaskCompleted(string id, AlmediaCompletedTask task)`

Fires `OnTaskCompleted`. If `id` is null or empty, the mock generates one. Delivery on a device is best-effort and can repeat. Call this method twice with the same id to reproduce a replay and to test your deduplication.

### `static void EmitBalanceChanged(string id, AlmediaRewardPoints balance, AlmediaRewardPoints change)`

Fires `OnBalanceChanged` with the balance after the change and the signed change. Pass negative coins and negative amounts in `change` to model a reversal.

### `static void EmitScreenPresented(AlmediaScreen screen)`

Fires `OnScreenPresented` for the given screen, without opening a real webview. Pair it with a later `EmitScreenDismissed` for the same screen to reproduce native's matched-pair contract in a test.

### `static void EmitScreenDismissed(AlmediaScreen screen, AlmediaInAppScreenResult result)`

Fires `OnScreenDismissed` for the given screen with the given result:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
AlmediaEditorMock.EmitScreenDismissed(AlmediaScreen.Offer,
    new AlmediaInAppScreenResult.Failed(new AlmediaError(AlmediaErrorCode.NetworkFailure, "offline")));
```

### `static void EmitNativeLog(AlmediaLogLevel level, string message)`

Delivers a forwarded log line through the same path the iOS/Android plugins use. Subscribers of `Almedia.OnLog` receive it as if it had come from the native side.

### `static void CancelPending()`

Stops any pending auto-simulate coroutine. Mostly relevant for tests that want to assert "no callback fires" after `Initialize` - call this immediately after `Almedia.Initialize` and the scheduled `Eligible` status never arrives. The first call to any other `Emit*` method calls this internally as part of the manual-mode flip.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.