diff --git a/frontend/src/lib/constants/environment.constants.ts b/frontend/src/lib/constants/environment.constants.ts index 9f07ece7da..2b2f22a9f9 100644 --- a/frontend/src/lib/constants/environment.constants.ts +++ b/frontend/src/lib/constants/environment.constants.ts @@ -18,18 +18,36 @@ export interface FeatureFlags { TEST_FLAG_EDITABLE: T; TEST_FLAG_NOT_EDITABLE: T; } +export const defaultFeatureFlagValues: FeatureFlags = { + ENABLE_CKTESTBTC: false, + DISABLE_IMPORT_TOKEN_VALIDATION_FOR_TESTING: false, + ENABLE_PERIODIC_FOLLOWING_CONFIRMATION: false, + ENABLE_EXPORT_NEURONS_REPORT: false, + TEST_FLAG_EDITABLE: false, + TEST_FLAG_NOT_EDITABLE: false, +}; export type FeatureKey = keyof FeatureFlags; +const getFeatureFlagsFromEnv = (): FeatureFlags => { + let featureFlags = {}; + try { + featureFlags = JSON.parse(envVars?.featureFlags); + } catch (e) { + console.error("Error parsing featureFlags", e); + } + // Complement the default flags with the ones from the environment to avoid missing flags. + return { ...defaultFeatureFlagValues, ...featureFlags }; +}; + /** * DO NOT USE DIRECTLY * * @see feature-flags.store.ts to use feature flags */ -export const FEATURE_FLAG_ENVIRONMENT: FeatureFlags = JSON.parse( - envVars?.featureFlags ?? - '{"ENABLE_CKTESTBTC": false, "ENABLE_SNS_TYPES_FILTER": false, "ENABLE_EXPORT_NEURONS_REPORT": false}' -); + +export const FEATURE_FLAG_ENVIRONMENT: FeatureFlags = + getFeatureFlagsFromEnv(); export const IS_TESTNET: boolean = DFX_NETWORK !== "mainnet" && diff --git a/frontend/src/tests/lib/api/canisters.api.spec.ts b/frontend/src/tests/lib/api/canisters.api.spec.ts index 2931d7b253..b8fd6183ef 100644 --- a/frontend/src/tests/lib/api/canisters.api.spec.ts +++ b/frontend/src/tests/lib/api/canisters.api.spec.ts @@ -422,6 +422,7 @@ describe("canisters-api", () => { }); it("should not notify if transfer fails", async () => { + vi.spyOn(console, "error").mockImplementation(() => undefined); mockLedgerCanister.transfer.mockRejectedValue(new Error()); const call = () => diff --git a/frontend/src/tests/lib/constants/environment.constants.spec.ts b/frontend/src/tests/lib/constants/environment.constants.spec.ts new file mode 100644 index 0000000000..8dc789b283 --- /dev/null +++ b/frontend/src/tests/lib/constants/environment.constants.spec.ts @@ -0,0 +1,53 @@ +import { defaultFeatureFlagValues } from "$lib/constants/environment.constants"; +import * as envVarsUtils from "$lib/utils/env-vars.utils"; + +describe("FEATURE_FLAG_ENVIRONMENT", () => { + const environmentVars = envVarsUtils.getEnvVars(); + + beforeEach(() => { + // The FEATURE_FLAG_ENVIRONMENT is a constant that is set once when the module + // `environment.constants` is imported. To test different states of it, + // we need to reset the imported modules and reimport `environment.constants` for each test. + vi.resetModules(); + }); + + it("should equal the environment values", async () => { + const { FEATURE_FLAG_ENVIRONMENT } = await import( + "$lib/constants/environment.constants" + ); + const expectedFlags = JSON.parse(environmentVars.featureFlags); + expect(FEATURE_FLAG_ENVIRONMENT).toEqual(expectedFlags); + }); + + it("should contain missing entries substituted with default values", async () => { + vi.spyOn(envVarsUtils, "getEnvVars").mockReturnValue({ + ...environmentVars, + featureFlags: JSON.stringify({}), + }); + + const { FEATURE_FLAG_ENVIRONMENT } = await import( + "$lib/constants/environment.constants" + ); + expect(FEATURE_FLAG_ENVIRONMENT).toEqual(defaultFeatureFlagValues); + }); + + it("should fallback to default on error", async () => { + const spyConsoleError = vi + .spyOn(console, "error") + .mockImplementation(() => undefined); + vi.spyOn(envVarsUtils, "getEnvVars").mockReturnValue({ + ...environmentVars, + featureFlags: `{"TEST_FLAG_NOT_EDITABLE": TRUE}`, + }); + + const { FEATURE_FLAG_ENVIRONMENT } = await import( + "$lib/constants/environment.constants" + ); + expect(FEATURE_FLAG_ENVIRONMENT).toEqual(defaultFeatureFlagValues); + expect(spyConsoleError).toBeCalledTimes(1); + expect(spyConsoleError).toBeCalledWith( + "Error parsing featureFlags", + new SyntaxError("Unexpected token T in JSON at position 27") + ); + }); +});