Skip to content

Commit

Permalink
feat(upgrade): adds featureflag-deprecate-flags-prop codemod and depr…
Browse files Browse the repository at this point in the history
…ecates flags prop (#17266)

* fix: add new props to feature flag props

* feat(upgrade): featureflag-deprecate-flags-prop codemod

* feat(upgrade): codemod, test cases and fixtures updated

* refactor: test fixtures

* refactor: sets default flag values to false at destructuring

* fix: skips transformation of files without FeatureFlags component

* refactor: makes conditions readable

* feat(upgrade):  removes old flags trasnformation, added tests

* feat(upgrade): adds codemod to @carbon/upgrade migrate

* chore: message updated

* feat(upgrade): tests updates, old flag removed

* fix: removes oldflag

* fix: added pattern matching for .ts & .tsx

* refactor: yarn dedupe changes

* refactor: yarn dedupe change, snapshotss

* fix: removes old flags, updates test outputs

---------

Co-authored-by: riddhybansal <[email protected]>
Co-authored-by: kennylam <[email protected]>
  • Loading branch information
3 people authored Sep 21, 2024
1 parent fd2495b commit 23b8ff3
Show file tree
Hide file tree
Showing 13 changed files with 640 additions and 64 deletions.
5 changes: 0 additions & 5 deletions packages/feature-flags/feature-flags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ feature-flags:
- name: enable-css-custom-properties
description: Describe what the flag does
enabled: false
- name: enable-use-controlled-state-with-value
description: >
Enable components to be created in either a controlled or uncontrolled
mode
enabled: false
- name: enable-css-grid
description: >
Enable CSS Grid Layout in the Grid and Column React components
Expand Down
22 changes: 15 additions & 7 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9801,14 +9801,22 @@ Map {
"children": Object {
"type": "node",
},
"flags": Object {
"args": Array [
Object {
"type": "bool",
},
],
"type": "objectOf",
"enableExperimentalFocusWrapWithoutSentinels": Object {
"type": "bool",
},
"enableTreeviewControllable": Object {
"type": "bool",
},
"enableV12Overflowmenu": Object {
"type": "bool",
},
"enableV12TileDefaultIcons": Object {
"type": "bool",
},
"enableV12TileRadioIcons": Object {
"type": "bool",
},
"flags": [Function],
},
},
"unstable_Layout" => Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ describe('FeatureFlags', () => {
expect(checkFlags).toHaveBeenLastCalledWith(true);
expect(checkFlag).toHaveBeenLastCalledWith(true);
});

it('should provide access to the feature flags for a scope', () => {
it('should provide access to the feature flags for a scope through deprecated flags prop', () => {
consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const checkFlags = jest.fn();
const checkFlag = jest.fn();

Expand Down Expand Up @@ -69,6 +69,49 @@ describe('FeatureFlags', () => {
a: true,
b: false,
});
consoleSpy.mockRestore();
});

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 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>
<TestComponent />
</FeatureFlags>
);

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

it('should re-render when flags change', () => {
Expand All @@ -77,104 +120,192 @@ describe('FeatureFlags', () => {

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

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

checkFlag({
a,
b,
enableV12Overflowmenu,
enableTreeviewControllable,
});

return null;
}

const { rerender } = render(
<FeatureFlags flags={{ a: true, b: false }}>
<FeatureFlags enableV12Overflowmenu>
<TestComponent />
</FeatureFlags>
);

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

rerender(
<FeatureFlags flags={{ a: false, b: true }}>
<FeatureFlags enableTreeviewControllable>
<TestComponent />
</FeatureFlags>
);

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

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

const checkFlag = jest.fn();

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

checkFlag({ global, local });
checkFlag({ enableV12Overflowmenu, enableTreeviewControllable });

return null;
}

render(
<FeatureFlags flags={{ local: true }}>
<FeatureFlags enableTreeviewControllable>
<TestComponent />
</FeatureFlags>
);

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

render(
<FeatureFlags flags={{ local: true }}>
<FeatureFlags flags={{ global: false }}>
<FeatureFlags enableTreeviewControllable>
<FeatureFlags enableV12Overflowmenu>
<TestComponent />
</FeatureFlags>
</FeatureFlags>
);

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

render(
<FeatureFlags flags={{ local: true }}>
<FeatureFlags flags={{ global: false }}>
<FeatureFlags flags={{ local: false }}>
<FeatureFlags enableTreeviewControllable>
<FeatureFlags enableV12Overflowmenu>
<FeatureFlags
enableTreeviewControllable={false}
enableV12Overflowmenu={false}>
<TestComponent />
</FeatureFlags>
</FeatureFlags>
</FeatureFlags>
);

expect(checkFlag).toHaveBeenLastCalledWith({
global: false,
local: false,
enableV12Overflowmenu: false,
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 enableExperimentalFocusWrapWithoutSentinels>
<TestComponent />
</FeatureFlags>
);

expect(checkFlags).toHaveBeenLastCalledWith({
enableV12Overflowmenu: false,
enableExperimentalFocusWrapWithoutSentinels: true,
});
expect(checkFlag).toHaveBeenLastCalledWith({
enableV12Overflowmenu: false,
enableExperimentalFocusWrapWithoutSentinels: true,
});
});
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,
});
});
});
Loading

0 comments on commit 23b8ff3

Please sign in to comment.