-
Notifications
You must be signed in to change notification settings - Fork 283
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Build time feature flags (Phase 1) (#694)
- Loading branch information
Showing
18 changed files
with
1,077 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# This is the debug/dev .env file. Any debug or non-release-signed build will | ||
# use these flags. | ||
|
||
# About flags: | ||
# ------------ | ||
# Any variables that start with flag_ will be available to the <Flag> component | ||
# For now, only true/1 is parsed, everything else will be interpretted as false | ||
# flags must begin with flag_ and are case sensitive | ||
|
||
flag_google_import=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# This is the BETA .env file, it is built for TestFlight and Google Play beta | ||
# channels. Flags that are ready for testing/beta should be enabled here. | ||
|
||
# When making any BETA channel build on both iOS or Android, prepend the build | ||
# command with ENVFILE=.env.beta | ||
# | ||
# e.g. | ||
# | ||
# ENVFILE=.env.beta ./gradlew assembleRelease | ||
|
||
# flag_google_import=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# This is the release .env file, it is built for App store final releases | ||
# only prod ready feature flags should be enabled here. | ||
# | ||
# For Android, this file is automatically used for any release build. iOS should | ||
# prepend ENVFILE=.env.release before any build commands. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default { | ||
FLAG_FOO_BAR: 'true', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
|
||
import { Flag } from '../helpers/flags'; | ||
|
||
/** | ||
* Small wrapper around `<Flag />` which makes the default case easier: | ||
* | ||
* Usage: | ||
* | ||
* ``` | ||
* <Feature name="google_import" fallback={() => <hr />}> | ||
* <FeatureUi /> | ||
* </Feature> | ||
* ``` | ||
* | ||
* @param {{ | ||
* name: string; | ||
* fallback?: () => import('react').ReactNode; | ||
* children: import('react').ReactNode; | ||
* }} param0 | ||
*/ | ||
export const Feature = ({ name, fallback, children }) => { | ||
const keyPath = name.split('.'); | ||
|
||
return ( | ||
<Flag name={keyPath} render={() => children} fallbackRender={fallback} /> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { render } from '@testing-library/react-native'; | ||
import React from 'react'; | ||
import { Text } from 'react-native'; | ||
|
||
import { FlagsProvider } from '../../helpers/flags'; | ||
import { Feature } from '../Feature'; | ||
|
||
it('renders feature if the flag is enabled', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{ feature1: true }}> | ||
<Feature name='feature1'> | ||
<Text>feature1</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('allows dotted notation in the feature name', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{ feature1: { child: true } }}> | ||
<Feature name='feature1.child'> | ||
<Text>feature1.child</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('does not render if dotted notation key path is falsy', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{ feature1: {} }}> | ||
<Feature name='feature1.child'> | ||
<Text>feature1.child</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('omits feature if the flag is disabled', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{ feature1: false }}> | ||
<Feature name='feature1'> | ||
<Text>feature1</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('omits feature if the flag is missing', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{}}> | ||
<Feature name='feature1'> | ||
<Text>feature1</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); | ||
|
||
it('renders the fallback instead, if the flag is disabled/omitted', () => { | ||
const { asJSON } = render( | ||
<FlagsProvider flags={{ feature1: false }}> | ||
<Feature name='feature1' fallback={() => <Text>Old UI</Text>}> | ||
<Text>feature1</Text> | ||
</Feature> | ||
</FlagsProvider>, | ||
); | ||
|
||
expect(asJSON()).toMatchSnapshot(); | ||
}); |
85 changes: 85 additions & 0 deletions
85
app/components/__tests__/__snapshots__/Feature.spec.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`allows dotted notation in the feature name 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
> | ||
<Text> | ||
feature1.child | ||
</Text> | ||
</View> | ||
`; | ||
|
||
exports[`does not render if dotted notation key path is falsy 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
/> | ||
`; | ||
|
||
exports[`omits feature if the flag is disabled 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
/> | ||
`; | ||
|
||
exports[`omits feature if the flag is missing 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
/> | ||
`; | ||
|
||
exports[`renders feature if the flag is enabled 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
> | ||
<Text> | ||
feature1 | ||
</Text> | ||
</View> | ||
`; | ||
|
||
exports[`renders the fallback instead, if the flag is disabled/omitted 1`] = ` | ||
<View | ||
collapsable={true} | ||
pointerEvents="box-none" | ||
style={ | ||
Object { | ||
"flex": 1, | ||
} | ||
} | ||
> | ||
<Text> | ||
Old UI | ||
</Text> | ||
</View> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import createFlags from 'flag'; | ||
import env from 'react-native-config'; | ||
|
||
const { FlagsProvider, Flag, useFlag, useFlags } = createFlags(); | ||
|
||
/** | ||
* Normalizes flags: | ||
* | ||
* Example: | ||
* | ||
* `{ flag_a: 'true' }` becomes `{ a: true }` | ||
* | ||
* @param {{[key: string]: string}} envConfig | ||
*/ | ||
export function parseFlags(envConfig) { | ||
return Object.entries(envConfig) | ||
.filter(([key]) => key.toLowerCase().startsWith('flag')) | ||
.reduce((flags, [key, value]) => { | ||
const flag = key.replace(/^flag_/i, ''); | ||
|
||
flags[flag] = value === 'true' || value === '1'; | ||
return flags; | ||
}, {}); | ||
} | ||
|
||
export const buildTimeFlags = parseFlags(env); | ||
|
||
export { FlagsProvider, Flag, useFlag, useFlags }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.