Skip to content

Commit

Permalink
Reintroduce Laika component (#90)
Browse files Browse the repository at this point in the history
* Reintroduce Laika component

* improved tests and added request delay

* add disabled test also for hook
  • Loading branch information
luxalpa authored Nov 3, 2021
1 parent 2c4fbd4 commit d787a76
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 15 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Changelog

## [1.1.0] - 2021-11-03

### Added

- Re-added Laika component. It can now use the context as well.
- Added this changelog

## [1.0.0] - 2021-11-02

### Changed

- This release is a complete rewrite in TypeScript which replaces the Laika component with a hook that can also optionally read its values from a context.

### Added

- Context
- `useLaika` hook
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,35 @@ function SomeComponent() {
}
```

### getFeatureStatus
### Component

```tsx
import React from 'react'
import { useLaika, Config, LaikaContext, Laika } from 'laika-react'
/* ... import your components ... */

const uri = 'https://laika.example.com'
const env = 'prod'

function SomeComponent() {
return (
<div>
<Laika
feature="component-test"
uri={uri} // You can leave out uri and env just like with the
// hook and have them be loaded from the context if you provided one
env={env}
onTrue={<NewComponent />}
onFalse={<OldComponent />}
/>
</div>
)
}
```



### Promise (getFeatureStatus)

```ts
import { getFeatureStatus } from 'laika-react'
Expand Down Expand Up @@ -131,6 +159,22 @@ Parameter | Function
`cacheTimeout` | The time how long a requested flag should be cached (default: 1.5 minutes).<br/>The flags and cache timestamps are saved in localstorage.
***Return values*** | Returns an array with 2 entries:<br/>1. `state`: The current state of the flag (`true` or `false`, defaults to `false` while the request is still resolving)<br/>2. `isLoading`: The second entry is true if it's still requesting the flag from the server and false if it's finished loading (useful for displaying loading indicators for example)

### `Laika` component

```tsx
interface LaikaProps {
feature: string
env?: string
uri?: string
cacheTimeout?: number,
onTrue: React.ReactElement | false
onFalse: React.ReactElement | false
}
```

Works analog to the `useLaika` hook, except that it's a component.
It will not render any children while the request is still loading the feature flag from Laika.

### `getFeatureStatus` utility function

Retrieves the feature flag from the API and returns a promise that can be `await`ed.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "laika-react",
"version": "1.0.0",
"version": "1.1.0",
"description": "React Laika client",
"homepage": "https://github.com/MEDIGO",
"keywords": [
Expand Down
60 changes: 60 additions & 0 deletions src/component.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { mount } from '@cypress/react'
import { Laika } from 'lib/component'
import { Config, LaikaContext } from 'lib/config'
import { mockRequest } from 'lib/mock/mockRequest'
import { cy, describe, it } from 'local-cypress'
import React from 'react'

describe('component', () => {
const uri = 'https://laika.example.com'

it('with-parameters', () => {
mockRequest('component-test', uri, 'test', true)

mount(
<Laika
feature="component-test"
uri={uri}
env="test"
onTrue={<div>Enabled</div>}
onFalse={<div>Disabled</div>}
/>,
)
cy.get('div').contains('Enabled')
})

it('with-parameters-disabled', () => {
mockRequest('component-test', uri, 'test', false)

mount(
<Laika
feature="component-test"
uri={uri}
env="test"
onTrue={<div>Enabled</div>}
onFalse={<div>Disabled</div>}
/>,
)
cy.get('div').contains('Disabled')
})

it('with-context', () => {
mockRequest('component-test', uri, 'test', true)

const ctx: Config = {
env: 'test',
uri,
}

mount(
<LaikaContext.Provider value={ctx}>
<Laika
feature="component-test"
onTrue={<div>Enabled</div>}
onFalse={<div>Disabled</div>}
/>
</LaikaContext.Provider>,
)
cy.get('div').contains('Enabled')
})
})
34 changes: 34 additions & 0 deletions src/component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { bool, node, number, oneOfType, string } from 'prop-types'
import React from 'react'
import { useLaika } from 'lib/hook'

export interface LaikaProps {
feature: string
env?: string
uri?: string
cacheTimeout?: number
onTrue: React.ReactElement | false
onFalse: React.ReactElement | false
}

export function Laika(props: LaikaProps) {
const [featureEnabled, featureIsLoading] = useLaika(
props.feature,
props.uri,
props.env,
props.cacheTimeout,
)

const children = featureEnabled ? props.onTrue : props.onFalse
return <>{!featureIsLoading && children}</>
}

// For using it with JavaScript
Laika.propTypes = {
feature: string.isRequired,
uri: string,
env: string,
cacheTimeout: number,
onTrue: oneOfType([node, bool]).isRequired,
onFalse: oneOfType([node, bool]).isRequired,
}
23 changes: 18 additions & 5 deletions src/hook.test.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { mount } from '@cypress/react'
import { Config, LaikaContext } from 'lib/config'
import { useLaika } from 'lib/hook'
import { mockRequest } from 'lib/mock/mockRequest'
import { cy, describe, it } from 'local-cypress'
import React from 'react'
import { useLaika } from './hook'
import { mockRequest } from './mock/mockRequest'
import { Config, LaikaContext } from './config'

describe('useLaika', () => {
const uri = 'https://laika.example.com'

it('with parameters', () => {
it('with-parameters', () => {
mockRequest('useLaika-test', uri, 'test', true)

function TestComp() {
Expand All @@ -21,7 +21,20 @@ describe('useLaika', () => {
cy.get('div').contains('Enabled')
})

it('with context', () => {
it('with-parameters-disabled', () => {
mockRequest('useLaika-test', uri, 'test', false)

function TestComp() {
const [flag] = useLaika('useLaika-test', uri, 'test')

return <div>{flag ? 'Enabled' : 'Disabled'}</div>
}

mount(<TestComp />)
cy.get('div').contains('Disabled')
})

it('with-context', () => {
mockRequest('useLaika-test', uri, 'test', true)

function TestComp() {
Expand Down
7 changes: 4 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { getFeatureStatus } from './utils'
export { useLaika } from './hook'
export { Config, LaikaContext } from './config'
export { getFeatureStatus } from 'lib/utils'
export { useLaika } from 'lib/hook'
export { Config, LaikaContext } from 'lib/config'
export { Laika } from 'lib/component'
1 change: 1 addition & 0 deletions src/mock/mockRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export function mockRequest(
headers: {
'content-type': 'application/json',
},
delay: 500,
})
}
10 changes: 5 additions & 5 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { cy, describe, it } from 'local-cypress'
import { mockRequest } from './mock/mockRequest'
import { getFeatureStatus } from './utils'
import { mockRequest } from 'lib/mock/mockRequest'
import { getFeatureStatus } from 'lib/utils'

describe('Utilities', () => {
describe('getFeatureStatus', () => {
it('acts on false', () => {
it('acts-on-false', () => {
mockRequest('cache-test', '', 'test', false)
.then(() => getFeatureStatus('cache-test', '', 'test'))
.should('eq', false)
})

it('acts on true', () => {
it('acts-on-true', () => {
mockRequest('cache-test', '', 'test', true)
.then(() => getFeatureStatus('cache-test', '', 'test'))
.should('eq', true)
})

it('caches the flag', () => {
it('caches-the-flag', () => {
cy.clock()
mockRequest('cache-test', '', 'test', true)
.then(() => getFeatureStatus('cache-test', '', 'test'))
Expand Down

0 comments on commit d787a76

Please sign in to comment.