Skip to main content

Testing Your Flag Integration

The @cuttlegate/sdk/testing module provides an in-process mock client for testing code that depends on feature flags. No running Cuttlegate server is required.

Installation

The test helper ships with @cuttlegate/sdk — no additional package needed.

npm install --save-dev @cuttlegate/sdk

Quick Start

import { createMockClient } from '@cuttlegate/sdk/testing';

const mock = createMockClient();

// Enable a boolean flag
mock.enable('dark-mode');

// Set a variant flag
mock.setVariant('button-color', 'blue');

// Use it like the real client
const result = await mock.evaluate('dark-mode', { user_id: 'user-1', attributes: {} });
console.log(result.enabled); // true

API

createMockClient(): MockCuttlegateClient

Creates a new mock client. All flags are disabled by default.

Flag Configuration

MethodDescription
mock.enable(key)Enable a boolean flag
mock.setVariant(key, value)Enable a flag with a specific variant value
mock.disable(key)Remove a flag's configuration (returns to default disabled)
mock.reset()Clear all flag configuration and evaluation tracking

Evaluation

The mock implements the same CuttlegateClient interface as the real client:

// Evaluate a single flag
const result = await mock.evaluate('my-flag', { user_id: 'user-1', attributes: {} });
// { key, enabled, variant, reason, evaluatedAt }

// Evaluate all configured flags
const results = await mock.evaluateAll({ user_id: 'user-1', attributes: {} });
// EvalResult[] — only flags that were explicitly configured

Default behaviour: unconfigured flags return { enabled: false, variant: '', reason: 'mock_default' }.

Assertions

MethodDescription
mock.assertEvaluated(key)Throws if the flag was never evaluated
mock.assertNotEvaluated(key)Throws if the flag was evaluated

Use assertions to verify your code actually checks the flags you expect:

const mock = createMockClient();
mock.enable('premium-feature');

await myService.handleRequest(mock, request);

mock.assertEvaluated('premium-feature');
mock.assertNotEvaluated('admin-override');

Example: Testing a Service

import { describe, it, expect, beforeEach } from 'vitest';
import { createMockClient } from '@cuttlegate/sdk/testing';
import { FeatureService } from './feature-service';

describe('FeatureService', () => {
let mock: ReturnType<typeof createMockClient>;
let service: FeatureService;

beforeEach(() => {
mock = createMockClient();
service = new FeatureService(mock);
});

it('shows dark mode when flag is enabled', async () => {
mock.enable('dark-mode');
const config = await service.getUIConfig({ user_id: 'user-1', attributes: {} });
expect(config.darkMode).toBe(true);
});

it('hides dark mode by default', async () => {
const config = await service.getUIConfig({ user_id: 'user-1', attributes: {} });
expect(config.darkMode).toBe(false);
});
});

Type Safety

MockCuttlegateClient extends CuttlegateClient, so it can be used anywhere the real client is expected — no type casting required:

import type { CuttlegateClient } from '@cuttlegate/sdk';

function myFunction(client: CuttlegateClient) {
// works with both real and mock clients
}