Wraps Optimizely Feature Experimentation SDK testing patterns - client init from a fixture datafile (offline-friendly), the decide / decideAll v5 API, forced-decisions for per-test arm pinning (fixing which variation a user gets), OptimizelyUserContext + activate/track events, assignment-integrity (deterministic bucketing) tests. Use when writing A/B tests or feature-flag tests for Optimizely-instrumented application code. For another experimentation SDK use the matching harness - statsig-test, vwo-test, amplitude-experiment-test, or split-io-test; for experiment DESIGN gates not SDK code use ab-test-validity-checklist.
80
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Optimizely Feature Experimentation (Optimizely Full Stack / Optimizely X) uses a datafile - a JSON blob describing all flags, experiments, and audiences - that the SDK fetches and evaluates locally. Per docs.developers.optimizely.com/feature-experimentation/docs/python-sdk, the SDK supports datafile-based testing: load a fixture datafile in tests, no network call.
The current API surface is decide (single flag) / decideAll
(all flags) per the v5 SDK.
pip install optimizely-sdk, or the npm package).tests/fixtures/.OptimizelyUserContext per test with the attributes the audience targeting needs.user.decide("new_checkout_flow").enabled is True - before pinning arms. If it fails, the datafile is stale or missing the flag; re-export it and re-run.set_forced_decision where a test needs a fixed variation, then call decide (one flag) or decide_all (all flags).variation_key / enabled (never variation IDs); add assignment-integrity and event-tracking checks via the notification listener (see references/optimizely-recipes.md).pip install optimizely-sdk # Python
npm install --save-dev @optimizely/optimizely-sdkPer Optimizely docs, the datafile path is the canonical offline approach:
import json
from optimizely import optimizely
# Load a checked-in datafile fixture
with open("tests/fixtures/optimizely-datafile.json") as f:
datafile = json.load(f)
client = optimizely.Optimizely(json.dumps(datafile))The datafile is downloadable from the Optimizely UI or via the Optimizely API; commit a version-specific copy to the repo for deterministic tests.
def test_get_decision_for_user():
user = client.create_user_context("user-1", {"plan": "premium"})
decision = user.decide("new_checkout_flow")
assert decision.enabled is True
assert decision.variation_key == "treatment_a"from optimizely.optimizely_user_context import OptimizelyDecisionContext
def test_force_user_to_treatment():
user = client.create_user_context("user-1")
context = OptimizelyDecisionContext(flag_key="new_checkout_flow", rule_key=None)
user.set_forced_decision(context, OptimizelyForcedDecision(variation_key="treatment_a"))
decision = user.decide("new_checkout_flow")
assert decision.variation_key == "treatment_a"Extended recipes - assignment-integrity and event-tracking tests, the pytest run command, and CI integration yaml - are in references/optimizely-recipes.md.
The team ships a new_checkout_flow flag with a treatment_a
variation, and QA needs a deterministic test that a premium-plan
user is routed into the treatment. Follow the How-to-use steps:
export the fixture, init offline, create the {"plan": "premium"}
context, assert decide("new_checkout_flow") returns enabled is True / variation_key == "treatment_a", then pin the arm with
set_forced_decision for the variant-specific path.
Result: a deterministic pass/fail on the checkout-routing logic with no network round-trip and no SDK key - the fixture drives the whole decision.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Tests with live SDK key | Production data polluted; rate-limited | Use datafile fixture |
| Datafile not version-controlled | Tests flake when prod config changes | Commit the fixture |
| Forced decisions leak across tests | Cross-test pollution | Per-test user context; reset before assertion |
Skipping client.shutdown / network listener cleanup | Goroutine / handle leak | Always cleanup |
| Asserting on variation IDs not keys | IDs change per environment | Use variation_key |
| Manual event tracking in tests vs notification listener | Misses platform-emitted events | Use the listener |
| Tests rely on real decide-network roundtrip | Slow; non-deterministic | Datafile + offline |
guardrail-metrics-reference,
peeking-problem-reference,
ab-test-validity-checklist.statsig-test,
vwo-test,
amplitude-experiment-test.