Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Issue 1418: [@s-ui/pde] use structured args in useFeature #1472

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ Packages must be properly named. 3 name are
* Folder: `./packages/sui-my-example-package`
* NPM name: `@s-ui/my-example-package`

### Versionning
### Versioning

We follow the [comver](https://github.com/staltz/comver) versionning this system (X.y.0).
We follow the [comver](https://github.com/staltz/comver) versioning this system (X.y.0).

Packages first version must be `1.0.0` (not 0.0.0)

Expand Down
17 changes: 10 additions & 7 deletions packages/sui-pde/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ It's possible to force a variation for our experiment in the browser. For exampl
import {useFeature} from '@s-ui/pde'

const MyComponent = () => {
const {isActive} = useFeature('myFeatureKey') // isActive = true when the feature flag is activated
const {isActive} = useFeature({featureKey: 'myFeatureKey'}) // isActive = true when the feature flag is activated

return <p>The feature 'myFeatureKey' is {isActive ? 'active' : 'inactive'}</p>
}
Expand Down Expand Up @@ -206,7 +206,7 @@ Returns all feature variables for the specified feature flag
import {useFeature} from '@s-ui/pde'

const MyComponent = () => {
const {isActive, variables} = useFeature('myFeatureKey') // variables = an object with all the feature variables
const {isActive, variables} = useFeature({featureKey: 'myFeatureKey'}) // variables = an object with all the feature variables

return (
<p>
Expand Down Expand Up @@ -237,8 +237,11 @@ In order to pass by attributes, you'll able to do so by adding the second argume
import {useFeature} from '@s-ui/pde'

const MyComponent = () => {
const {isActive} = useFeature('myFeatureKey', {
isLoggedIn: true // this second parameter are the attributes
const {isActive} = useFeature({
featureKey: 'myFeatureKey',
attributes: {
isLoggedIn: true // this second parameter are the attributes
}
})

return <p>The feature 'myFeatureKey' is {isActive ? 'active' : 'inactive'}</p>
Expand Down Expand Up @@ -292,9 +295,9 @@ Using the hooks

```js
const MyComponent = () => {
const defaultFeature = useFeature('myFeatureKey') // will return the {isActive, variables} object from the default optimizely instance
const alsoDefaultFeature = useFeature('myFeatureKey', null, null, 'default') // will return the {isActive, variables} object from the default optimizely instance
const alternateFeature = useFeature('myFeatureKey', null, null, 'alternative') // will return the {isActive, variables} object from the alternate optimizely instance
const defaultFeature = useFeature({featureKey: 'myFeatureKey'}) // will return the {isActive, variables} object from the default optimizely instance
const alsoDefaultFeature = useFeature({featureKey: 'myFeatureKey', adapterId: 'default'}) // will return the {isActive, variables} object from the default optimizely instance
const alternateFeature = useFeature({featureKey: 'myFeatureKey', adapterId: 'alternative'}) // will return the {isActive, variables} object from the alternate optimizely instance

const defaultExperiment = useExperiment({experimentName: 'myExperimentName'}) // will return the experiment object from the default optimizely instance
const alsoDefaultExperiment = useExperiment({experimentName: 'myExperimentName', adapterId: 'default'}) // will return the experiment object from the default optimizely instance
Expand Down
13 changes: 11 additions & 2 deletions packages/sui-pde/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@s-ui/pde",
"version": "2.20.0",
"version": "3.0.0",
"description": "",
"type": "module",
"main": "lib/index.js",
Expand Down Expand Up @@ -29,5 +29,14 @@
"@testing-library/react-hooks": "4.0.1",
"react": "17",
"react-test-renderer": "17"
},
"eslintConfig": {
"extends": [
"./node_modules/@s-ui/lint/eslintrc.js"
]
},
"prettier": "./node_modules/@s-ui/lint/.prettierrc.js",
"stylelint": {
"extends": "./node_modules/@s-ui/lint/stylelint.config.js"
}
}
}
6 changes: 5 additions & 1 deletion packages/sui-pde/src/components/feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export default function Feature({
attributes,
queryString
}) {
const {isActive, variables} = useFeature(featureKey, attributes, queryString)
const {isActive, variables} = useFeature({
featureKey,
attributes,
queryString
})
return children({isActive, variables})
}

Expand Down
13 changes: 7 additions & 6 deletions packages/sui-pde/src/hooks/useFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,19 @@ const trackLinkedExperimentsViewed = ({

/**
* Hook to use a feature toggle
* @param {string} featureKey
* @param {object} attributes
* @param {string} [queryString] test purposes only
* @param {string} adapterId
* @param {object} param
* @param {string} param.featureKey
* @param {object} param.attributes
* @param {string} param.[queryString] test purposes only
* @param {string} param.adapterId
* @return {{isActive: boolean}}
*/
export default function useFeature(
export default function useFeature({
featureKey,
attributes,
queryString,
adapterId
) {
} = {}) {
const {pde} = useContext(PdeContext)
if (pde === null)
throw new Error('[useFeature] sui-pde provider is required to work')
Expand Down
77 changes: 52 additions & 25 deletions packages/sui-pde/test/common/useFeatureSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ describe('when pde context is set', () => {

it('should check if a feature is enabled', () => {
const {result} = renderHook(
() => useFeature('featureKey1', {attribute1: 'value'}),
() =>
useFeature({
featureKey: 'featureKey1',
attributes: {attribute1: 'value'}
}),
{wrapper}
)
expect(result.current.isActive).to.equal(true)
Expand All @@ -53,7 +57,11 @@ describe('when pde context is set', () => {

it('should return feature variables', () => {
const {result} = renderHook(
() => useFeature('featureKey2', {attribute1: 'value'}),
() =>
useFeature({
featureKey: 'featureKey2',
attributes: {attribute1: 'value'}
}),
{wrapper}
)

Expand All @@ -69,7 +77,11 @@ describe('when pde context is set', () => {
describe.client('and the hook is executed by the browser', () => {
it('should check that a feature has been forced to be active', () => {
const {result} = renderHook(
() => useFeature('featureKey3', {}, '?suipde_feature1=on'),
() =>
useFeature({
featureKey: 'featureKey3',
queryString: '?suipde_feature1=on'
}),
{wrapper}
)
expect(result.current.isActive).to.equal(true)
Expand All @@ -78,11 +90,10 @@ describe('when pde context is set', () => {
it('should check that a feature has been forced to be not active', () => {
const {result} = renderHook(
() =>
useFeature(
'featureKey3',
{},
'?suipde_featureKey3=off&suipde_feature1=on'
),
useFeature({
featureKey: 'featureKey3',
queryString: '?suipde_featureKey3=off&suipde_feature1=on'
}),
{wrapper}
)
expect(result.current.isActive).to.equal(false)
Expand Down Expand Up @@ -128,7 +139,7 @@ describe('when pde context is set', () => {
})

it('should send the on state experiment viewed', () => {
renderHook(() => useFeature('activeFeatureFlagKey'), {
renderHook(() => useFeature({featureKey: 'activeFeatureFlagKey'}), {
wrapper
})
expect(window.analytics.track.args[0][0]).to.equal(
Expand All @@ -142,12 +153,18 @@ describe('when pde context is set', () => {

describe.client('when a feature is seen twice', () => {
it('should only track one experiment viewed event', () => {
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
wrapper
})
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
wrapper
})
renderHook(
() => useFeature({featureKey: 'repeatedFeatureFlagKey'}),
{
wrapper
}
)
renderHook(
() => useFeature({featureKey: 'repeatedFeatureFlagKey'}),
{
wrapper
}
)
expect(window.analytics.track.args.length).to.equal(1)
})
})
Expand Down Expand Up @@ -184,9 +201,12 @@ describe('when pde context is set', () => {
})

it('should send the off state experiment viewed', () => {
renderHook(() => useFeature('notActiveFeatureFlagKey'), {
wrapper
})
renderHook(
() => useFeature({featureKey: 'notActiveFeatureFlagKey'}),
{
wrapper
}
)
expect(window.analytics.track.args[0][0]).to.equal(
'Experiment Viewed'
)
Expand Down Expand Up @@ -238,9 +258,16 @@ describe('when pde context is set', () => {
})

it('should send experiment viewed event for every test asociated and the experiment viewed associated to the feature flag itself', () => {
renderHook(() => useFeature('featureKey4', {attribute1: 'value'}), {
wrapper
})
renderHook(
() =>
useFeature({
featureKey: 'featureKey4',
attributes: {attribute1: 'value'}
}),
{
wrapper
}
)

// feature being called
expect(window.analytics.track.args[0][0]).to.equal('Experiment Viewed')
Expand Down Expand Up @@ -315,10 +342,10 @@ describe('when pde context is set', () => {
stubFactory(isFeatureEnabled)
})
it('should send only one experiment viewed event', () => {
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
renderHook(() => useFeature({featureKey: 'repeatedFeatureFlagKey'}), {
wrapper
})
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
renderHook(() => useFeature({featureKey: 'repeatedFeatureFlagKey'}), {
wrapper
})
expect(window.analytics.track.args.length).to.equal(1)
Expand All @@ -338,10 +365,10 @@ describe('when pde context is set', () => {
stubFactory(isFeatureEnabled)
})
it('should send two experiment viewed events', () => {
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
renderHook(() => useFeature({featureKey: 'repeatedFeatureFlagKey'}), {
wrapper
})
renderHook(() => useFeature('repeatedFeatureFlagKey'), {
renderHook(() => useFeature({featureKey: 'repeatedFeatureFlagKey'}), {
wrapper
})
expect(window.analytics.track.args.length).to.equal(2)
Expand Down