Testland
Browse all skills & agents

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.

Install with skills.sh (any agent)

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

unleash-testing

When to use

  • Tests for code that calls unleash.isEnabled(flagName, context).
  • Tests for custom Unleash strategies (the extensibility point).
  • Assignment-integrity tests per ab-test-validity-checklist.

Authoring

Install

npm install --save-dev unleash-client
pip install UnleashClient

Bootstrap with toggles (offline)

import { initialize } from 'unleash-client';

const unleash = initialize({
  url: 'http://localhost:4242/api/',
  appName: 'test-app',
  disableMetrics: true,        // No metrics upload
  disablePolling: true,        // No background polling
  bootstrap: {
    data: [
      {
        name: 'show-new-ui',
        enabled: true,
        strategies: [
          { name: 'default' },
        ],
      },
    ],
  },
});

// Wait for initialization
await new Promise<void>((resolve) => unleash.once('synchronized', resolve));

The bootstrap.data array is the SDK's initial flag state; since polling is disabled, that state persists for the test session.

isEnabled tests

test('flag enabled', () => {
  expect(unleash.isEnabled('show-new-ui')).toBe(true);
});

test('flag with context', () => {
  expect(unleash.isEnabled('premium-only', { userId: 'u1', properties: { tier: 'premium' } })).toBe(true);
});

Custom strategy

Unleash's extensibility: custom strategies implement an isEnabled(parameters, context) method.

import { Strategy } from 'unleash-client';

class TenantStrategy extends Strategy {
  constructor() { super('tenantStrategy'); }
  isEnabled(parameters: any, context: any): boolean {
    const allowedTenants = (parameters.tenants ?? '').split(',');
    return allowedTenants.includes(context.tenantId);
  }
}

const unleash = initialize({
  url: '...',
  appName: 'test',
  strategies: [new TenantStrategy()],
  bootstrap: {
    data: [
      {
        name: 'flag-x',
        enabled: true,
        strategies: [{ name: 'tenantStrategy', parameters: { tenants: 'A,B' } }],
      },
    ],
  },
});

test('strategy allows tenant A', () => {
  expect(unleash.isEnabled('flag-x', { tenantId: 'A' })).toBe(true);
});

test('strategy rejects tenant C', () => {
  expect(unleash.isEnabled('flag-x', { tenantId: 'C' })).toBe(false);
});

Percentage-rollout determinism

const unleash = initialize({
  // ...
  bootstrap: {
    data: [
      {
        name: 'gradual-rollout',
        enabled: true,
        strategies: [{ name: 'flexibleRollout', parameters: { rollout: '50', stickiness: 'userId' } }],
      },
    ],
  },
});

test('rollout deterministic per user', () => {
  const r1 = unleash.isEnabled('gradual-rollout', { userId: 'u1' });
  const r2 = unleash.isEnabled('gradual-rollout', { userId: 'u1' });
  expect(r1).toBe(r2);
});

Teardown

afterAll(() => unleash.destroy());

Running

npm test

CI integration

jobs:
  unleash-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
      - run: npm ci && npm test

Fully offline - no Unleash server URL needed since polling is disabled.

Anti-patterns

Anti-patternWhy it failsFix
disableMetrics: false in CISpurious metrics POSTsAlways disableMetrics: true in tests
disablePolling: false without test-only URLNetwork calls; CI flakesAlways disable polling in offline tests
bootstrap.data is staleDrift from prod definitionsPull from Unleash periodically; commit fixture
Custom strategies not unit-testedLogic bugs in the strategy itselfTest the strategy class in isolation too
Skipping synchronized event waitRace: isEnabled returns defaultAlways await synchronized
Forgetting unleash.destroy()Goroutine / timer leakAlways destroy in afterAll
Tests use real Unleash serverSlow; flaky if server downBootstrap mode

Limitations

  • Bootstrap is point-in-time. Drift between fixture + Unleash UI is invisible.
  • Custom strategies tested in isolation lose context. Integration test with the full SDK still needed.
  • Metric-side tests need real server. If you're testing the metrics export path, bootstrap mode is wrong.
  • Stickiness is parameter-driven. A misconfigured stickiness parameter shows up in production, not in tests.

References

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.

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.

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.