1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 09:13:33 +00:00

[EC-473] Add feature flags to common code (#3324)

This commit is contained in:
Thomas Rittson
2022-08-26 13:00:14 +10:00
committed by GitHub
parent aed78a5b61
commit 90137936fa
10 changed files with 261 additions and 114 deletions

View File

@@ -0,0 +1,99 @@
import { flagEnabled, devFlagEnabled, devFlagValue } from "./flags";
describe("flagEnabled", () => {
beforeEach(() => {
process.env.FLAGS = JSON.stringify({});
});
it("returns true by default", () => {
expect(flagEnabled<any>("nonExistentFlag")).toBe(true);
});
it("returns true if enabled", () => {
process.env.FLAGS = JSON.stringify({
newFeature: true,
});
expect(flagEnabled<any>("newFeature")).toBe(true);
});
it("returns false if disabled", () => {
process.env.FLAGS = JSON.stringify({
newFeature: false,
});
expect(flagEnabled<any>("newFeature")).toBe(false);
});
});
describe("devFlagEnabled", () => {
beforeEach(() => {
process.env.DEV_FLAGS = JSON.stringify({});
});
describe("in a development environment", () => {
beforeEach(() => {
process.env.ENV = "development";
});
it("returns true by default", () => {
expect(devFlagEnabled<any>("nonExistentFlag")).toBe(true);
});
it("returns true if enabled", () => {
process.env.DEV_FLAGS = JSON.stringify({
devHack: true,
});
expect(devFlagEnabled<any>("devHack")).toBe(true);
});
it("returns true if truthy", () => {
process.env.DEV_FLAGS = JSON.stringify({
devHack: { key: 3 },
});
expect(devFlagEnabled<any>("devHack")).toBe(true);
});
it("returns false if disabled", () => {
process.env.DEV_FLAGS = JSON.stringify({
devHack: false,
});
expect(devFlagEnabled<any>("devHack")).toBe(false);
});
});
it("always returns false in prod", () => {
process.env.ENV = "production";
process.env.DEV_FLAGS = JSON.stringify({
devHack: true,
});
expect(devFlagEnabled<any>("devHack")).toBe(false);
});
});
describe("devFlagValue", () => {
beforeEach(() => {
process.env.DEV_FLAGS = JSON.stringify({});
process.env.ENV = "development";
});
it("throws if dev flag is disabled", () => {
process.env.DEV_FLAGS = JSON.stringify({
devHack: false,
});
expect(() => devFlagValue<any>("devHack")).toThrow("it is protected by a disabled dev flag");
});
it("returns the dev flag value", () => {
process.env.DEV_FLAGS = JSON.stringify({
devHack: "Hello world",
});
expect(devFlagValue<any>("devHack")).toBe("Hello world");
});
});

View File

@@ -0,0 +1,61 @@
// required to avoid linting errors when there are no flags
/* eslint-disable @typescript-eslint/ban-types */
export type SharedFlags = {};
// required to avoid linting errors when there are no flags
/* eslint-disable @typescript-eslint/ban-types */
export type SharedDevFlags = {};
function getFlags<T>(envFlags: string | T): T {
if (typeof envFlags === "string") {
return JSON.parse(envFlags) as T;
} else {
return envFlags as T;
}
}
/**
* Gets the value of a feature flag from environment.
* All flags default to "on" (true).
* Only use for shared code in `libs`, otherwise use the client-specific function.
* @param flag The name of the feature flag to check
* @returns The value of the flag
*/
export function flagEnabled<Flags extends SharedFlags>(flag: keyof Flags): boolean {
const flags = getFlags<Flags>(process.env.FLAGS);
return flags[flag] == null || !!flags[flag];
}
/**
* Gets the value of a dev flag from environment.
* Will always return false unless in development.
* Only use for shared code in `libs`, otherwise use the client-specific function.
* @param flag The name of the dev flag to check
* @returns The value of the flag
*/
export function devFlagEnabled<DevFlags extends SharedDevFlags>(flag: keyof DevFlags): boolean {
if (process.env.ENV !== "development") {
return false;
}
const devFlags = getFlags<DevFlags>(process.env.DEV_FLAGS);
return devFlags[flag] == null || !!devFlags[flag];
}
/**
* Gets the value of a dev flag from environment.
* Will always return false unless in development.
* @param flag The name of the dev flag to check
* @returns The value of the flag
* @throws Error if the flag is not enabled
*/
export function devFlagValue<DevFlags extends SharedDevFlags>(
flag: keyof DevFlags
): DevFlags[keyof DevFlags] {
if (!devFlagEnabled(flag)) {
throw new Error(`This method should not be called, it is protected by a disabled dev flag.`);
}
const devFlags = getFlags<DevFlags>(process.env.DEV_FLAGS);
return devFlags[flag];
}