Skip to content

Commit 1acd6fd

Browse files
authored
fix(flags): handle plain array and object forms in overrideFeatureFlags (#3245)
* fix overrides * Address PR feedback: extract helper and use parameterised tests - Extract arrayToFlagsRecord helper to eliminate duplicated array-to-flags-object conversion - Refactor tests to use it.each for parameterised testing * Address PR feedback: narrow return type and log invalid options - Narrow arrayToFlagsRecord return type from Record<string, string | boolean> to Record<string, true> - Replace unreachable _fireFeatureFlagsCallbacks call with warning log for invalid overrideOptions * add changeset
1 parent 7efa558 commit 1acd6fd

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

.changeset/honest-rats-raise.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'posthog-js': patch
3+
'@posthog/types': patch
4+
---
5+
6+
handle plain array and object forms in overrideFeatureFlags

packages/browser/src/__tests__/featureflags.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,33 @@ describe('featureflags', () => {
958958
})
959959
})
960960

961+
describe('plain array and object shorthand forms', () => {
962+
it.each([
963+
['plain array', ['beta-feature', 'alpha-feature-2'], { 'beta-feature': true, 'alpha-feature-2': true }],
964+
[
965+
'plain object',
966+
{ 'beta-feature': 'variant-1', 'alpha-feature-2': false },
967+
{ 'beta-feature': 'variant-1', 'alpha-feature-2': false },
968+
],
969+
])('supports %s shorthand form for flag overrides', (_, input, expected) => {
970+
featureFlags.overrideFeatureFlags(input as any)
971+
expect(featureFlags.getFlagVariants()).toEqual(expected)
972+
})
973+
974+
it('plain object does not affect payloads', () => {
975+
featureFlags.overrideFeatureFlags({ 'beta-feature': 'variant-1' })
976+
977+
expect(featureFlags.getFlagVariants()).toEqual({
978+
'beta-feature': 'variant-1',
979+
'alpha-feature-2': true,
980+
})
981+
expect(featureFlags.getFlagPayloads()).toEqual({
982+
'beta-feature': { original: 'payload' },
983+
'alpha-feature-2': 123,
984+
})
985+
})
986+
})
987+
961988
describe('callback behavior', () => {
962989
let callbackSpy: jest.Mock
963990

packages/browser/src/posthog-featureflags.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ const PERSISTENCE_FEATURE_FLAG_PAYLOADS = '$feature_flag_payloads'
6161
const PERSISTENCE_OVERRIDE_FEATURE_FLAG_PAYLOADS = '$override_feature_flag_payloads'
6262
const PERSISTENCE_FEATURE_FLAG_REQUEST_ID = '$feature_flag_request_id'
6363

64+
/** Converts an array of flag names to a Record where each flag is set to true. */
65+
const arrayToFlagsRecord = (flags: string[]): Record<string, true> => {
66+
const flagsObj: Record<string, true> = {}
67+
for (let i = 0; i < flags.length; i++) {
68+
flagsObj[flags[i]] = true
69+
}
70+
return flagsObj
71+
}
72+
6473
export const filterActiveFeatureFlags = (featureFlags?: Record<string, string | boolean>) => {
6574
const activeFeatureFlags: Record<string, string | boolean> = {}
6675
for (const [key, value] of entries(featureFlags || {})) {
@@ -946,6 +955,8 @@ export class PostHogFeatureFlags implements Extension {
946955
* - posthog.featureFlags.overrideFeatureFlags(false) // clear all overrides
947956
* - posthog.featureFlags.overrideFeatureFlags(['beta-feature']) // enable flags
948957
* - posthog.featureFlags.overrideFeatureFlags({'beta-feature': 'variant'}) // set variants
958+
* - posthog.featureFlags.overrideFeatureFlags({ flags: ['beta-feature'] }) // enable flags
959+
* - posthog.featureFlags.overrideFeatureFlags({ flags: {'beta-feature': 'variant'} }) // set variants
949960
* - posthog.featureFlags.overrideFeatureFlags({ // set both flags and payloads
950961
* flags: {'beta-feature': 'variant'},
951962
* payloads: { 'beta-feature': { someData: true } }
@@ -968,6 +979,15 @@ export class PostHogFeatureFlags implements Extension {
968979
return forceDebugLogger.info('All overrides cleared')
969980
}
970981

982+
// Array syntax: ['flag-a', 'flag-b'] -> { 'flag-a': true, 'flag-b': true }
983+
if (isArray(overrideOptions)) {
984+
const flagsObj = arrayToFlagsRecord(overrideOptions)
985+
this._instance.persistence.register({ [PERSISTENCE_OVERRIDE_FEATURE_FLAGS]: flagsObj })
986+
this._fireFeatureFlagsCallbacks()
987+
988+
return forceDebugLogger.info('Flag overrides set', { flags: overrideOptions })
989+
}
990+
971991
if (
972992
overrideOptions &&
973993
typeof overrideOptions === 'object' &&
@@ -983,10 +1003,7 @@ export class PostHogFeatureFlags implements Extension {
9831003
forceDebugLogger.info('Flag overrides cleared')
9841004
} else if (options.flags) {
9851005
if (isArray(options.flags)) {
986-
const flagsObj: Record<string, string | boolean> = {}
987-
for (let i = 0; i < options.flags.length; i++) {
988-
flagsObj[options.flags[i]] = true
989-
}
1006+
const flagsObj = arrayToFlagsRecord(options.flags)
9901007
this._instance.persistence.register({ [PERSISTENCE_OVERRIDE_FEATURE_FLAGS]: flagsObj })
9911008
} else {
9921009
this._instance.persistence.register({ [PERSISTENCE_OVERRIDE_FEATURE_FLAGS]: options.flags })
@@ -1013,7 +1030,17 @@ export class PostHogFeatureFlags implements Extension {
10131030
return
10141031
}
10151032

1016-
this._fireFeatureFlagsCallbacks()
1033+
// Fallback: treat as Record<string, string | boolean>, e.g. {'beta-feature': 'variant'}
1034+
if (overrideOptions && typeof overrideOptions === 'object') {
1035+
this._instance.persistence.register({
1036+
[PERSISTENCE_OVERRIDE_FEATURE_FLAGS]: overrideOptions as Record<string, string | boolean>,
1037+
})
1038+
this._fireFeatureFlagsCallbacks()
1039+
1040+
return forceDebugLogger.info('Flag overrides set', { flags: overrideOptions })
1041+
}
1042+
1043+
logger.warn('Invalid overrideOptions provided to overrideFeatureFlags', { overrideOptions })
10171044
}
10181045

10191046
/*

packages/types/src/posthog.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ export interface PostHog {
218218
* flags: {'beta-feature': 'variant'},
219219
* payloads: { 'beta-feature': { someData: true } }
220220
* })
221+
* posthog.featureFlags.overrideFeatureFlags({ // only override payloads
222+
* payloads: { 'beta-feature': { someData: true } }
223+
* })
221224
* ```
222225
*/
223226
overrideFeatureFlags(overrideOptions: OverrideFeatureFlagsOptions): void

0 commit comments

Comments
 (0)