Testing
For unit tests, configure Shipeasy in test mode with configureForTesting(...) — a drop-in sibling of configure(...) that does zero network, needs no API…
Generated from the SDK's own /docs/ — also served raw at
https://shipeasy-ai.github.io/sdk-swift/pages/testing.md.
For unit tests, configure Shipeasy in test mode with configureForTesting(...)
— a drop-in sibling of configure(...) that does zero network, needs no API
key, and is immediately ready. Seed the values your code under test should see,
then read them through the ordinary bound Client. It replaces any previous
configuration, so each test can reconfigure freely.
import Shipeasy
// no key, no network; seed what the code under test should see
await configureForTesting(
flags: ["new_checkout": true], // [name: Bool]
configs: ["billing_copy": ["headline": "50% off"]], // [name: Any?]
experiments: ["checkout_button": (group: "treatment", // [name: (group, params)]
params: ["color": "green"])]
)
// construct once per callsite (cheap; binds the user)
let client = try Client(["user_id": "u_123"])
await client.getFlag("new_checkout", default: false) // true
await client.getConfig("billing_copy") // ["headline": "50% off"]
let r = await client.getExperiment("checkout_button", defaultParams: nil)
// r.inExperiment == true, r.group == "treatment", r.params == ["color": "green"]
// track()/logExposure() are no-ops in test mode — safe to call, never send.
await client.track("purchase")The seed maps:
flags: [String: Bool]— forcedgetFlagresults.configs: [String: Any?]— forcedgetConfigresults.experiments: [String: (group: String, params: Any?)]— forced enrolments.
On-the-spot overrides
Layer additional forced values on top of whatever you configured with the
package-level override helpers (all async). An override always wins until you
clearOverrides():
await overrideFlag("FLAG_KEY", true)
await overrideConfig("CONFIG_KEY", ["headline": "hi"])
await overrideExperiment("EXPERIMENT_KEY", group: "treatment", params: ["color": "green"])
// drop every on-the-spot override (and, in test mode, the seed too — test mode has
// no blob beneath, so everything reverts to empty-blob defaults)
await clearOverrides()Under configureForOffline (below), clearOverrides() leaves the snapshot in
place — evaluations revert to the snapshot rather than empty defaults.
Offline snapshots
configureForOffline(...) evaluates the real rules from a snapshot with no
network — a drop-in sibling of configure(...) (no API key). Provide exactly one
source: a path to a JSON file, or an in-memory snapshot. Optional
flags/configs/experiments overrides layer on top.
// From a JSON file on disk
try await configureForOffline(path: "/path/to/snapshot.json")
// …or an in-memory snapshot: ["flags": <flags blob>, "experiments": <experiments blob>]
try await configureForOffline(snapshot: [
"flags": ["gates": [:], "configs": [:], "killswitches": [:]],
"experiments": ["experiments": [:], "universes": [:]]
])
let client = try Client(["user_id": "u_123"])
let on = await client.getFlag("new_checkout")The snapshot file format
A snapshot file is a single JSON object with a flags blob (the body of
/sdk/flags) and an experiments blob (the body of /sdk/experiments):
{
"flags": {
"gates": {
"new_checkout": { "enabled": true, "rolloutPct": 10000, "salt": "s" }
},
"configs": {
"billing_copy": { "headline": "Welcome" }
},
"killswitches": {}
},
"experiments": {
"experiments": {},
"universes": {}
}
}A gate is { "enabled": true, "rolloutPct": 10000, "salt": "s" } where
rolloutPct is in basis points — 10000 is 100%, 1000 is 10%, 0 is off.
configs maps a config name to its JSON value. Empty killswitches /
experiments / universes objects are valid.
Error reporting — `see()`
The Swift SDK ships the full see() structured-error surface. Every handled exception documents its product consequence, not just its stack. Reports are…
OpenFeature
The Swift SDK does not ship an OpenFeature provider. There is no OpenFeature module, provider type, or adapter in the package — the source tree contains no…