Testland
Browse all skills & agents

flagsmith-testing

Wraps Flagsmith server-side SDK testing patterns (feature flags / feature toggles) so tests run without calling the Flagsmith API: offline mode with LocalFileHandler + a downloaded environment.json snapshot, local-evaluation mode (no per-request network), and default_flag_handler for per-feature mocked fallbacks, via the get_environment_flags / get_identity_flags evaluation paths. Use when writing feature-flag tests for code that uses Flagsmith, mocking flag values, or testing feature toggles offline in CI.

Install with skills.sh (any agent)

npx skills add testland/qa --skill flagsmith-testing
View source

flagsmith-testing

Overview

Flagsmith (open-source, also SaaS at flagsmith.com) supports three test-friendly modes per docs.flagsmith.com/clients/server-side (opens in new window):

  1. Offline mode with LocalFileHandler - loads a downloaded environment.json snapshot; zero network.
  2. Local-evaluation mode - fetches environment + flags periodically, evaluates locally without per-request network.
  3. Default flag handler - programmatic fallback for any flag (mock-flag-only mode).

Offline mode is the default choice for tests; local-evaluation and default_flag_handler detail live in references/flagsmith-modes.md.

When to use

  • Tests for code using Flagsmith flags.
  • Fully-offline CI without Flagsmith network access.
  • Mocking specific flag values via default_flag_handler.

How to use

  1. Install the SDK: pip install flagsmith (Python) or npm install --save-dev flagsmith-nodejs (Node).
  2. Download the environment snapshot with the Flagsmith CLI (command below) and commit it as a test fixture.
  3. Construct the client in offline mode with LocalFileHandler pointed at that fixture, so tests make zero network calls.
  4. For flags not yet in the snapshot, register a default_flag_handler returning a DefaultFlag with the value under test (see references/flagsmith-modes.md).
  5. Evaluate via get_environment_flags() for environment-scoped flags, or get_identity_flags(identifier, traits=...) for per-user flags.
  6. Assert on is_feature_enabled(...) and get_feature_value(...), and add an integrity test that the same identity resolves consistently.
  7. Verify: with offline_mode=True and no environment_key set, get_environment_flags() must return the fixture's flags with zero network calls (run the suite with the machine offline or under a network-blocking fixture to confirm). If it raises or attempts an API call, the LocalFileHandler environment_document_path is wrong or offline_mode is unset - fix the path and re-run.
  8. Wire pytest tests/flagsmith/ into CI - offline mode needs no env vars.

Offline mode with LocalFileHandler

Per docs.flagsmith.com (opens in new window):

from flagsmith import Flagsmith
from flagsmith.offline_handlers import LocalFileHandler

local_file_handler = LocalFileHandler(environment_document_path="tests/fixtures/flagsmith-environment.json")

flagsmith = Flagsmith(offline_mode=True, offline_handler=local_file_handler)

Download the environment.json via the Flagsmith CLI, then commit it (refresh deliberately):

flagsmith environment-document --api-key=<server-key> --output=tests/fixtures/flagsmith-environment.json

Evaluate flags

def test_environment_flag():
    flags = flagsmith.get_environment_flags()
    assert flags.is_feature_enabled("secret_button") is False
    assert flags.get_feature_value("secret_button") == '{"colour": "#b8b8b8"}'

def test_identity_flag():
    flags = flagsmith.get_identity_flags(
        identifier="user@example.com",
        traits={"plan": "premium"},
    )
    assert flags.is_feature_enabled("premium_feature") is True

Integrity test - the same identity must resolve consistently:

def test_same_identity_consistent():
    f1 = flagsmith.get_identity_flags("u1")
    f2 = flagsmith.get_identity_flags("u1")
    assert f1.is_feature_enabled("flag-x") == f2.is_feature_enabled("flag-x")

CI integration

jobs:
  flagsmith-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v5
      - run: pip install flagsmith
      - run: pytest tests/flagsmith/

No env vars needed in offline mode.

Worked example

A service reads a secret_button flag (boolean plus a JSON colour value) and a premium_feature flag gated on a plan trait, tested fully offline:

  1. Download the environment document and commit it (step 2 above).
  2. Build the offline client with LocalFileHandler (offline-mode snippet above).
  3. secret_button is not in the snapshot yet, so register a default_flag_handler for it (see references/flagsmith-modes.md).
  4. Assert on get_environment_flags() and get_identity_flags(...) (evaluate snippet above).

Result: pytest tests/flagsmith/ runs green in CI with zero network access and no analytics pollution.

References

Flagsmith test modes, anti-patterns, and limitations

View source (opens in new window)

Flagsmith test modes, anti-patterns, and limitations

Deeper detail for flagsmith-testing (opens in new window). Offline mode (covered in the skill spine) is the default for tests; the modes below are secondary.

Local-evaluation mode

Polls the Flagsmith API periodically and evaluates flags locally between refreshes (no per-request network, but not zero network):

flagsmith = Flagsmith(
    environment_key="server-key",
    enable_local_evaluation=True,
    environment_refresh_interval_seconds=60,
)

Local mode polls; offline mode does not. For tests, offline is usually preferred.

default_flag_handler - per-flag mock

Programmatic fallback used when the offline environment.json does not have the flag under test yet:

from flagsmith import Flagsmith
from flagsmith.models import DefaultFlag

def default_flag_handler(feature_name: str) -> DefaultFlag:
    if feature_name == "secret_button":
        return DefaultFlag(enabled=False, value='{"colour": "#b8b8b8"}')
    return DefaultFlag(enabled=False, value=None)

flagsmith = Flagsmith(
    environment_key="test-key",
    default_flag_handler=default_flag_handler,
)

Useful when the offline environment.json does not have the flag you are testing yet.

Anti-patterns

Anti-patternWhy it failsFix
Production env_key in testsReal API calls + analytics pollutionoffline_mode + LocalFileHandler
environment.json not committedTest flakes when prod changesCommit; refresh deliberately
Mixing offline_mode + local_evaluation_modeConflicting; one takes precedencePick one
default_flag_handler returns DefaultFlag with no valueTests for value-based flags fail silentlyAlways set value
Skipping flagsmith.get_identity_flags for identity-scoped testsBypasses per-user logicUse identity API
Per-test new Flagsmith clientSlow initSession-scoped fixture

Limitations

  • environment.json is point-in-time. Drift invisible.
  • default_flag_handler only fires for missing flags in local-eval mode. In offline mode it can be used for fallback.
  • No granular per-user override API. Use traits + segments via the environment.json.
  • Doesn't validate Flagsmith's own logic. Platform-side evaluation is separate.

Related skills

feature-flag-test-matrix-reference

Pure-reference catalog of feature-flag test matrix design. Defines the flag-state combinatorics problem (N flags × M variants × K user-segments = N×M×K test cases), the canonical coverage strategies (pairwise interaction coverage; default-only smoke; full matrix; risk-driven matrix), the kill-switch + percentage-rollout test patterns, and the relationship between flags + experiments (flags toggle behaviour; experiments measure outcome). Use when designing the flag-test surface for a new project or auditing existing flag-test coverage.

flag-removal-runbook-author

Workflow-driven skill that builds the runbook for safely removing a feature flag from the codebase + the flag platform. Walks through: pre-removal verification (flag fully rolled out, no usage variance in evaluations, dependent code paths identified), the code-removal steps (delete the if-branches, simplify, restore types), the platform-side removal (archive in LaunchDarkly / Unleash / Flagsmith / GrowthBook), the verification post-removal, and the rollback plan. Use when removing a flag that has finished its mission (rollout-complete, experiment-shipped, kill-switch retired).

flag-state-coverage-builder

Workflow-driven skill that builds a flag-state coverage matrix from the project's flag inventory and risk register. Walks through: inventorying flags (grep for flag-evaluation calls), classifying each (boolean / multi-variant / kill-switch / experiment), choosing the coverage strategy (per-flag-isolation / pairwise / full / risk-driven per feature-flag-test-matrix-reference), generating the test matrix (PICT for pairwise; manual for risk-driven), and emitting test skeletons. Use when introducing flag-test coverage to a new codebase or when a flag-related incident exposes a coverage gap.

growthbook-testing

Wraps GrowthBook Node SDK testing patterns: GrowthBookClient initialization with direct payload (initSync; no network), isOn / getFeatureValue / evalFeature, scoped instances (createScopedInstance) for per-request user context, inline experiment (runInlineExperiment) tests, and tracking-callback assertion patterns. Use when writing tests for code using GrowthBook for flags + experiments.

killswitch-test-author

Workflow-driven skill that authors the four test categories specific to kill-switch (ops-toggle) flags: switch-OFF graceful degradation, fail-static default when the flag service is unreachable, latency budget for the kill decision, and no-data-corruption mid-flight. Distinct from flag-state-coverage-builder (which builds a full coverage matrix across all flag types) and feature-flag-test-matrix-reference (which catalogs patterns without producing tests). Use when a kill-switch flag exists in the codebase and needs dedicated, production-incident-rehearsing tests authored for it.

launchdarkly-testing

Wraps LaunchDarkly server-side SDK testing patterns: TestData data source for hermetic tests (no network), file-based data source for fixture-driven tests, flag override patterns (TestData.update for per-test flag values), and assignment-integrity tests. Use when writing tests for code that uses LaunchDarkly flags.

openfeature-sdk-testing

Wraps OpenFeature (CNCF vendor-neutral SDK abstraction) testing patterns: the InMemoryProvider for hermetic tests without network calls, provider registration via OpenFeature.setProvider, the getBooleanValue/getBooleanDetails evaluation API with EvaluationDetails (value, variant, reason, errorCode), hooks for evaluation side-effects, and evaluation context for targeting-rule tests. Covers TypeScript, Java, and Python SDKs. Use when writing tests for code that resolves feature flags through the OpenFeature SDK regardless of the underlying flag management platform.

unleash-testing

Wraps Unleash (Open Source / SaaS) SDK testing patterns: bootstrap with a static toggles array (no network), the test mode (disableMetrics + disablePolling), the custom strategy testing pattern (implement a Strategy class + assert isEnabled), and assignment-integrity tests. Use when writing tests for code that uses Unleash for feature flags.