Skip to content

Commit

Permalink
fix: add new props to feature flag props
Browse files Browse the repository at this point in the history
  • Loading branch information
riddhybansal committed Aug 22, 2024
1 parent 5e4632c commit 58ab74c
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 4 deletions.
18 changes: 18 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9814,6 +9814,24 @@ Map {
"children": Object {
"type": "node",
},
"enableExperimentalFocusWrapWithoutSentinels": Object {
"type": "bool",
},
"enableTreeviewControllable": Object {
"type": "bool",
},
"enableUseControlledStateWithValue": Object {
"type": "bool",
},
"enableV12Overflowmenu": Object {
"type": "bool",
},
"enableV12TileDefaultIcons": Object {
"type": "bool",
},
"enableV12TileRadioIcons": Object {
"type": "bool",
},
"flags": Object {
"args": Array [
Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,46 @@ describe('FeatureFlags', () => {
});
});

it('should provide access to the feature flags for a scope', () => {
const checkFlags = jest.fn();
const checkFlag = jest.fn();

function TestComponent() {
const featureFlags = useFeatureFlags();
const flag1 = useFeatureFlag('enable-v12-overflowmenu');
const flag2 = useFeatureFlag('enable-treeview-controllable');

checkFlags({
enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
enableTreeviewControllable: featureFlags.enabled(
'enable-treeview-controllable'
),
});

checkFlag({
enableV12Overflowmenu: flag1,
enableTreeviewControllable: flag2,
});

return null;
}

render(
<FeatureFlags enableV12Overflowmenu enableTreeviewControllable={false}>
<TestComponent />
</FeatureFlags>
);

expect(checkFlags).toHaveBeenLastCalledWith({
enableV12Overflowmenu: true,
enableTreeviewControllable: false,
});
expect(checkFlag).toHaveBeenLastCalledWith({
enableV12Overflowmenu: true,
enableTreeviewControllable: false,
});
});

it('should re-render when flags change', () => {
const checkFlags = jest.fn();
const checkFlag = jest.fn();
Expand Down Expand Up @@ -124,6 +164,94 @@ describe('FeatureFlags', () => {
});
});

it('should handle boolean props correctly when no flags object is provided', () => {
const checkFlags = jest.fn();
const checkFlag = jest.fn();

function TestComponent() {
const featureFlags = useFeatureFlags();
const enableV12Overflowmenu = useFeatureFlag('enable-v12-overflowmenu');
const enableTreeviewControllable = useFeatureFlag(
'enable-treeview-controllable'
);

checkFlags({
enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
enableTreeviewControllable: featureFlags.enabled(
'enable-treeview-controllable'
),
});

checkFlag({
enableV12Overflowmenu,
enableTreeviewControllable,
});

return null;
}

render(
<FeatureFlags enableV12Overflowmenu enableTreeviewControllable={false}>
<TestComponent />
</FeatureFlags>
);

expect(checkFlags).toHaveBeenLastCalledWith({
enableV12Overflowmenu: true,
enableTreeviewControllable: false,
});
expect(checkFlag).toHaveBeenLastCalledWith({
enableV12Overflowmenu: true,
enableTreeviewControllable: false,
});
});

it('should handle boolean props and flags object with no overlapping keys', () => {
const checkFlags = jest.fn();
const checkFlag = jest.fn();

function TestComponent() {
const featureFlags = useFeatureFlags();
const enableV12Overflowmenu = useFeatureFlag('enable-v12-overflowmenu');
const enableExperimentalFocusWrapWithoutSentinels = useFeatureFlag(
'enable-experimental-focus-wrap-without-sentinels'
);

checkFlags({
enableV12Overflowmenu: featureFlags.enabled('enable-v12-overflowmenu'),
enableExperimentalFocusWrapWithoutSentinels: featureFlags.enabled(
'enable-experimental-focus-wrap-without-sentinels'
),
});

checkFlag({
enableV12Overflowmenu,
enableExperimentalFocusWrapWithoutSentinels,
});

return null;
}

render(
<FeatureFlags
flags={{
'enable-v12-overflowmenu': false,
}}
enableExperimentalFocusWrapWithoutSentinels>
<TestComponent />
</FeatureFlags>
);

expect(checkFlags).toHaveBeenLastCalledWith({
enableV12Overflowmenu: false,
enableExperimentalFocusWrapWithoutSentinels: true,
});
expect(checkFlag).toHaveBeenLastCalledWith({
enableV12Overflowmenu: false,
enableExperimentalFocusWrapWithoutSentinels: true,
});
});

it('should merge scopes and overwrite duplicate keys', () => {
GlobalFeatureFlags.add('global', true);

Expand Down
34 changes: 30 additions & 4 deletions packages/react/src/components/FeatureFlags/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,37 @@ const FeatureFlagContext = createContext(GlobalFeatureFlags);
* along with the current `FeatureFlagContext` to provide consumers to check if
* a feature flag is enabled or disabled in a given React tree
*/
function FeatureFlags({ children, flags = {} }) {
function FeatureFlags({
children,
flags = {},
enableUseControlledStateWithValue,
enableV12TileDefaultIcons,
enableV12TileRadioIcons,
enableV12Overflowmenu,
enableTreeviewControllable,
enableExperimentalFocusWrapWithoutSentinels,
}) {
const parentScope = useContext(FeatureFlagContext);
const [prevParentScope, setPrevParentScope] = useState(parentScope);

const combinedFlags = {
'enable-use-controlled-state-with-value': enableUseControlledStateWithValue,
'enable-v12-tile-default-icons': enableV12TileDefaultIcons,
'enable-v12-tile-radio-icons': enableV12TileRadioIcons,
'enable-v12-overflowmenu': enableV12Overflowmenu,
'enable-treeview-controllable': enableTreeviewControllable,
'enable-experimental-focus-wrap-without-sentinels':
enableExperimentalFocusWrapWithoutSentinels,
...flags,
};
const [scope, updateScope] = useState(() => {
const scope = createScope(flags);
const scope = createScope(combinedFlags);
scope.mergeWithScope(parentScope);
return scope;
});

if (parentScope !== prevParentScope) {
const scope = createScope(flags);
const scope = createScope(combinedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
setPrevParentScope(parentScope);
Expand All @@ -48,7 +68,7 @@ function FeatureFlags({ children, flags = {} }) {
// We use a custom hook to detect if any of the keys or their values change
// for flags that are passed in. If they have changed, then we re-create the
// FeatureFlagScope using the new flags
useChangedValue(flags, isEqual, (changedFlags) => {
useChangedValue(combinedFlags, isEqual, (changedFlags) => {
const scope = createScope(changedFlags);
scope.mergeWithScope(parentScope);
updateScope(scope);
Expand All @@ -68,6 +88,12 @@ FeatureFlags.propTypes = {
* Provide the feature flags to enabled or disabled in the current React tree
*/
flags: PropTypes.objectOf(PropTypes.bool),
enableUseControlledStateWithValue: PropTypes.bool,
enableV12TileDefaultIcons: PropTypes.bool,
enableV12TileRadioIcons: PropTypes.bool,
enableV12Overflowmenu: PropTypes.bool,
enableTreeviewControllable: PropTypes.bool,
enableExperimentalFocusWrapWithoutSentinels: PropTypes.bool,
};

/**
Expand Down

0 comments on commit 58ab74c

Please sign in to comment.