Writing tests with flags

Client SDKs provide some utility methods that allow you to override their behavior and prevent real API calls. This is specially useful while doing automated tests. These methods provide 3 different levels of granularity:

  • Global level: disable or enable all flags.
  • Flag level: disable or enable a specific flag.
  • Actor level: disable or enable a flag for specific actors.

Examples:

const client = new GroundControlClient({
  apiKey: YOUR_API_KEY,
  projectId: YOUR_PROJECT_ID,
});

// global level
client.enableAllFeatureFlags();
client.disableAllFeatureFlags();

// flag level
client.enableFeatureFlag(flagName);
client.disableFeatureFlag(flagName);

// actor level
client.enableFeatureFlag(flagName, { actors: ["user1"] });
client.disableFeatureFlag(flagName, { actors: ["user1"] });

You can always remove all overrides by calling client.reset().

More granular overrides take precedence over less granular overrides. For example you can disable all flags, but enable only one, or even only one for a specific actor. Example:

const client = new GroundControlClient({
  apiKey: YOUR_API_KEY,
  projectId: YOUR_PROJECT_ID,
});

client.disableAllFeatureFlags();
client.enableFeatureFlag(flagName, { actors: ["user1"] }); // this override takes precedence

// the flag is enabled at this point for `user1`.

Consider running all tests twice

A good practice to try to cover all code paths is to run all your tests twice. One time with all flags disabled, and another time with all flags disabled.

const client = new GroundControlClient({
  apiKey: YOUR_API_KEY,
  projectId: YOUR_PROJECT_ID,
});

if (process.env.ENABLE_ALL_FEATURE_FLAGS) {
  client.enableAllFeatureFlags();
} else {
  client.disableAllFeatureFlags();
}

test("something", async () => {
  //
});

Then you can run your tests like this:

npm t # all feature flags disabled by default

export ENABLE_ALL_FEATURE_FLAGS=1

npm t # all feature flags enabled by default

In your CI/CD pipeline you can have two jobs that run in parallel, each one with a different global configuration.